├── README.md ├── include ├── command.h ├── context.h ├── dispatcher.h ├── env.h ├── errorlog.h ├── fibernet.h ├── group_mgr.h ├── handle.h ├── harbor.h ├── lib │ ├── 2darray.h │ ├── astar.h │ ├── bellman_ford.h │ ├── binary_search_tree.h │ ├── bitset.h │ ├── bloom_filter.h │ ├── dijkstra.h │ ├── directed_graph.h │ ├── dos_tree.h │ ├── double_linked_list.h │ ├── edmonds_karp.h │ ├── generic.h │ ├── graph_defs.h │ ├── graph_search.h │ ├── hash_multi.h │ ├── hash_string.h │ ├── hash_table.h │ ├── heap.h │ ├── huffman.h │ ├── imath.h │ ├── insertion_sort.h │ ├── integer.h │ ├── interval_tree.h │ ├── lcs.h │ ├── md5.h │ ├── merge_sort.h │ ├── perfect_hash.h │ ├── prim_mst.h │ ├── prime.h │ ├── priority_queue.h │ ├── queue.h │ ├── quick_sort.h │ ├── radix_sort.h │ ├── random.h │ ├── random_select.h │ ├── rbtree.h │ ├── rbtree_defs.h │ ├── sha1.h │ ├── shuffle.h │ ├── skip_list.h │ ├── sol.h │ ├── stack.h │ ├── undirected_graph.h │ ├── universal_hash.h │ └── word_seg.h ├── module.h ├── monitor.h ├── mq.h ├── multicast.h ├── rwlock.h └── timer.h └── src ├── context.cpp ├── handle.cpp ├── harbor.cpp └── mq.cpp /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xtaci/fibernet/85005cbd18d9eddc129d18d4e8ef2119d6cab601/README.md -------------------------------------------------------------------------------- /include/command.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIBERNET_COMMAND_H__ 2 | #define __FIBERNET_COMMAND_H__ 3 | 4 | namespace fibernet 5 | { 6 | /** 7 | * command sub-system 8 | */ 9 | class Command 10 | { 11 | public: 12 | /** 13 | * execute a command under context. 14 | */ 15 | const char * exec(Context * ctx, const char * cmd , const char * param) 16 | { 17 | /** 18 | * Syntax: TIMEOUT N*10ms 19 | * a new session id is returned 20 | * when time's up, a message is delivered with 21 | * the same session id 22 | */ 23 | if (strcmp(cmd,"TIMEOUT") == 0) { 24 | char * session_ptr = NULL; 25 | int ti = strtol(param, &session_ptr, 10); 26 | int session = ctx->newsession(); 27 | if (session < 0) 28 | return NULL; 29 | skynet_timeout(ctx->handle(), ti, session); 30 | sprintf(ctx->result, "%d", session); 31 | return ctx->result; 32 | } 33 | 34 | /** 35 | * Syntax: LOCK 36 | * lock the MQ, the message delivered to this MQ is not dispatched 37 | * after the session sent a message. 38 | */ 39 | if (strcmp(cmd,"LOCK") == 0) { 40 | if (ctx->init == false) { 41 | return NULL; 42 | } 43 | ctx->queue->lock(ctx->session_id+1); 44 | return NULL; 45 | } 46 | 47 | /** 48 | * Syntax: REG / REG .name / REG harbor 49 | * 1. get context handle 50 | * 2. register a name 51 | * 3. register to harbor 52 | */ 53 | if (strcmp(cmd,"REG") == 0) { 54 | if (param == NULL || param[0] == '\0') { 55 | sprintf(ctx->result, ":%x", ctx->handle); 56 | return ctx->result; 57 | } else if (param[0] == '.') { 58 | return Handle::instance()->reg_name(ctx->handle, param + 1); 59 | } else { 60 | assert(ctx->handle!=0); 61 | struct remote_name *rname = malloc(sizeof(*rname)); 62 | _copy_name(rname->name, param); 63 | rname->handle = ctx->handle; 64 | skynet_harbor_register(rname); 65 | return NULL; 66 | } 67 | } 68 | 69 | /** 70 | * Syntax: NAME name :handle 71 | * name a :handle, like REG 72 | */ 73 | if (strcmp(cmd,"NAME") == 0) { 74 | int size = strlen(param); 75 | char name[size+1]; 76 | char handle[size+1]; 77 | sscanf(param,"%s %s",name,handle); 78 | if (handle[0] != ':') { 79 | return NULL; 80 | } 81 | uint32_t handle_id = strtoul(handle+1, NULL, 16); 82 | if (handle_id == 0) { 83 | return NULL; 84 | } 85 | if (name[0] == '.') { 86 | return skynet_handle_namehandle(handle_id, name + 1); 87 | } else { 88 | struct remote_name *rname = malloc(sizeof(*rname)); 89 | _copy_name(rname->name, name); 90 | rname->handle = handle_id; 91 | skynet_harbor_register(rname); 92 | } 93 | return NULL; 94 | } 95 | 96 | /** 97 | * Synax: NOW 98 | * get current time, in 10ms 99 | */ 100 | if (strcmp(cmd,"NOW") == 0) { 101 | uint32_t ti = skynet_gettime(); 102 | sprintf(ctx->result,"%u",ti); 103 | return ctx->result; 104 | } 105 | 106 | /** 107 | * Syntax EXIT 108 | * destroy context 109 | */ 110 | if (strcmp(cmd,"EXIT") == 0) { 111 | Handle::instance()->retire(ctx->handle); 112 | return NULL; 113 | } 114 | 115 | /** 116 | * Syntax: KILL :handle / KILL .name 117 | */ 118 | if (strcmp(cmd,"KILL") == 0) { 119 | uint32_t handle = 0; 120 | if (param[0] == ':') { 121 | handle = strtoul(param+1, NULL, 16); 122 | } else if (param[0] == '.') { 123 | handle = skynet_handle_findname(param+1); 124 | } else { 125 | skynet_error(context, "Can't kill %s",param); 126 | // todo : kill global service 127 | } 128 | if (handle) { 129 | Handle::instance()->retire(handle); 130 | } 131 | return NULL; 132 | } 133 | 134 | /** 135 | * Syntax: LAUNCH name param 136 | * Launch a module with parm, return handle in hex; 137 | */ 138 | if (strcmp(cmd,"LAUNCH") == 0) { 139 | size_t sz = strlen(param); 140 | char tmp[sz+1]; 141 | strcpy(tmp,param); 142 | char * args = tmp; 143 | char * mod = strsep(&args, " \t\r\n"); 144 | args = strsep(&args, "\r\n"); 145 | Context * new_ctx = ContextFactory::create(mod,args); 146 | if (inst == NULL) { 147 | fprintf(stderr, "Launch %s %s failed\n",mod,args); 148 | return NULL; 149 | } else { 150 | _id_to_hex(ctx->result, new_ctx->handle); 151 | return ctx->result; 152 | } 153 | } 154 | 155 | /** 156 | * Syntax: GETENV key 157 | * Application level environment variable 158 | */ 159 | if (strcmp(cmd,"GETENV") == 0) { 160 | return skynet_getenv(param); 161 | } 162 | 163 | /** 164 | * Syntax: SETENV key value 165 | */ 166 | if (strcmp(cmd,"SETENV") == 0) { 167 | size_t sz = strlen(param); 168 | char key[sz+1]; 169 | int i; 170 | for (i=0;param[i] != ' ' && param[i];i++) { 171 | key[i] = param[i]; 172 | } 173 | if (param[i] == '\0') 174 | return NULL; 175 | 176 | key[i] = '\0'; 177 | param += i+1; 178 | 179 | skynet_setenv(key,param); 180 | return NULL; 181 | } 182 | 183 | /** 184 | * Syntax: STARTTIME 185 | * starttime in secs, since epoch 186 | */ 187 | if (strcmp(cmd,"STARTTIME") == 0) { 188 | uint32_t sec = skynet_gettime_fixsec(); 189 | sprintf(ctx->result,"%u",sec); 190 | return ctx->result; 191 | } 192 | 193 | /** 194 | * GROUP commands, see _group_command 195 | */ 196 | if (strcmp(cmd,"GROUP") == 0) { 197 | int sz = strlen(param); 198 | char tmp[sz+1]; 199 | strcpy(tmp,param); 200 | tmp[sz] = '\0'; 201 | char cmd[sz+1]; 202 | int group_handle=0; 203 | uint32_t addr=0; 204 | sscanf(tmp, "%s %d :%x",cmd,&group_handle,&addr); 205 | return _group_command(context, cmd, group_handle,addr); 206 | } 207 | 208 | /** 209 | * syntax: ENDLESS 210 | * set endless 211 | */ 212 | if (strcmp(cmd,"ENDLESS") == 0) { 213 | if (ctx->endless) { 214 | strcpy(ctx->result, "1"); 215 | ctx->endless = false; 216 | return ctx->result; 217 | } 218 | return NULL; 219 | } 220 | 221 | /** 222 | * syntax: ABORT 223 | * destroy all context 224 | */ 225 | if (strcmp(cmd,"ABORT") == 0) { 226 | Handle::instance()->retireall(); 227 | return NULL; 228 | } 229 | 230 | return NULL; 231 | } 232 | private: 233 | /** 234 | * group command, start with GROUP command params 235 | */ 236 | static const char * _group_command(Context * ctx, const char * cmd, int group_handle, uint32_t addr) 237 | { 238 | uint32_t self; 239 | if (addr != 0) { 240 | if (skynet_harbor_message_isremote(v)) { 241 | skynet_error(ctx, "Can't add remote handle %x",v); 242 | return NULL; 243 | } 244 | self = addr; 245 | } else { 246 | self = ctx->handle; 247 | } 248 | 249 | /** 250 | * Syntax: ENTER group_handle handle / ENTER group_handle 251 | */ 252 | if (strcmp(cmd, "ENTER") == 0) { 253 | GroupManager::instance()->enter(group_handle, self); 254 | return NULL; 255 | } 256 | 257 | /** 258 | * Syntax: LEAVE group_handle handle / LEAVE group_handle 259 | */ 260 | if (strcmp(cmd, "LEAVE") == 0) { 261 | GroupManager::instance()->leave(group_handle, self); 262 | return NULL; 263 | } 264 | 265 | /** 266 | * Syntax: QUERY group_handle 267 | */ 268 | if (strcmp(cmd, "QUERY") == 0) { 269 | uint32_t addr = GroupManager::instance()->query(group_handle); 270 | if (addr == 0) { 271 | return NULL; 272 | } 273 | _id_to_hex(ctx->result, addr); 274 | return ctx->result; 275 | } 276 | 277 | /** 278 | * Syntax: CLEAR group_handle 279 | */ 280 | if (strcmp(cmd, "CLEAR") == 0) { 281 | GroupManager::instance()->clear(group_handle); 282 | return NULL; 283 | } 284 | 285 | return NULL; 286 | } 287 | 288 | static void _id_to_hex(char * str, uint32_t id) 289 | { 290 | int i; 291 | static char hex[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; 292 | str[0] = ':'; 293 | for (i=0;i<8;i++) { 294 | str[i+1] = hex[(id >> ((7-i) * 4))&0xf]; 295 | } 296 | str[9] = '\0'; 297 | } 298 | 299 | static void _copy_name(char name[GLOBALNAME_LENGTH], const char * addr) 300 | { 301 | int i; 302 | for (i=0;i 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "module.h" 10 | #include "mq.h" 11 | #include "handle.h" 12 | 13 | #ifdef CALLING_CHECK 14 | 15 | #define CHECKCALLING_BEGIN(ctx) assert(__sync_lock_test_and_set(&ctx->calling,1) == 0); 16 | #define CHECKCALLING_END(ctx) __sync_lock_release(&ctx->calling); 17 | #define CHECKCALLING_INIT(ctx) ctx->calling = 0; 18 | #define CHECKCALLING_DECL int calling; 19 | 20 | #else 21 | 22 | #define CHECKCALLING_BEGIN(ctx) 23 | #define CHECKCALLING_END(ctx) 24 | #define CHECKCALLING_INIT(ctx) 25 | #define CHECKCALLING_DECL 26 | 27 | #endif 28 | 29 | namespace fibernet 30 | { 31 | class Context 32 | { 33 | private: 34 | Module * m_mod; // the module 35 | void * m_instance; // result of xxx_create 36 | 37 | uint32_t m_handle; // handle 38 | int m_sess_id; 39 | 40 | char m_result[32]; // storing non-integer result 41 | void * m_ud; // user data 42 | fibernet_cb m_cb; // call back function 43 | 44 | MQ * queue; // mq 45 | 46 | uint32_t m_forward; // forward to another ctx 47 | bool m_init; 48 | bool m_endless; 49 | int m_ref; // ref count 50 | 51 | static int g_total_context; 52 | 53 | CHECKCALLING_DECL 54 | 55 | friend class ContextFactory; 56 | friend class Dispatcher; 57 | friend class Command; 58 | 59 | public: 60 | void init(uint32_t handle) { m_handle = handle; } 61 | uint32_t handle() { return m_handle; } 62 | 63 | void callback(void *ud, fibernet_cb cb) 64 | { 65 | m_cb = cb; 66 | m_ud = ud; 67 | } 68 | 69 | int newsession() 70 | { 71 | int session = ++m_sess_id; 72 | return session; 73 | } 74 | 75 | void grab() { __sync_add_and_fetch(&m_ref,1); } 76 | 77 | void send(void * msg, size_t sz, uint32_t source, int type, int session); 78 | static int push(uint32_t handle, MQ::Message *message); 79 | static void endless(uint32_t handle); 80 | Context * release(); 81 | 82 | /** 83 | * forward the message of to another context. 84 | */ 85 | void forward(uint32_t destination) 86 | { 87 | assert(m_forward == 0); 88 | m_forward = destination; 89 | } 90 | 91 | static int context_total() { return g_total_context; } 92 | static void context_inc() { __sync_fetch_and_add(&g_total_context,1); } 93 | static void context_dec() { __sync_fetch_and_sub(&g_total_context,1); } 94 | 95 | private: 96 | Context(); 97 | Context(const Context&); 98 | Context& operator= (const Context&); 99 | void _delete_context(); 100 | }; 101 | 102 | class ContextFactory { 103 | public: 104 | static Context * create(const char * name, const char *param); 105 | }; 106 | } 107 | 108 | 109 | #endif // 110 | -------------------------------------------------------------------------------- /include/dispatcher.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIBERNET_DISPATCHER_H__ 2 | #define __FIBERNET_DISPATCHER_H__ 3 | 4 | namespace fibernet 5 | { 6 | class Dispatcher { 7 | public: 8 | 9 | /** 10 | * core message dispatcher 11 | */ 12 | static int dispatch(struct skynet_monitor *sm) 13 | { 14 | // pop one MQ 15 | MQ * q = GlobalMQ::pop(); 16 | 17 | if (q==NULL) 18 | return 1; 19 | 20 | uint32_t handle = q->handle(); 21 | Context * ctx = Handle::instance()->grab(handle); 22 | // if the context is released, release the MQ 23 | if (ctx == NULL) { 24 | int s = q->release(); 25 | if (s>0) { 26 | skynet_error(NULL, "Drop message queue %x (%d messages)", handle, s); 27 | } 28 | return 0; 29 | } 30 | 31 | // pop one piece of message from the MQ. 32 | Message msg; 33 | if (!q->pop(&msg)) { 34 | ctx->release(); 35 | return 0; 36 | } 37 | 38 | skynet_monitor_trigger(sm, msg.source , handle); 39 | 40 | // when callback function is not defined. 41 | if (ctx->cb == NULL) { 42 | free(msg.data); 43 | skynet_error(NULL, "Drop message from %x to %x without callback , size = %d",msg.source, handle, (int)msg.sz); 44 | } else { 45 | _dispatch_message(ctx, &msg); 46 | } 47 | 48 | // push to global queue again. 49 | assert(q == ctx->queue); 50 | q->pushglobal(); 51 | ctx->release(); 52 | skynet_monitor_trigger(sm, 0,0); 53 | 54 | return 0; 55 | } 56 | 57 | /** 58 | * send message from context to destination. 59 | * source can be faked for purpose. 60 | */ 61 | int send(Context * context, uint32_t source, uint32_t destination , int type, int session, void * data, size_t sz) 62 | { 63 | _filter_args(context, type, &session, (void **)&data, &sz); 64 | 65 | if (source == 0) { 66 | source = context->handle; 67 | } 68 | 69 | if (destination == 0) { 70 | return session; 71 | } 72 | if (skynet_harbor_message_isremote(destination)) { 73 | struct remote_message * rmsg = malloc(sizeof(*rmsg)); 74 | rmsg->destination.handle = destination; 75 | rmsg->message = data; 76 | rmsg->sz = sz; 77 | skynet_harbor_send(rmsg, source, session); 78 | } else { 79 | struct skynet_message smsg; 80 | smsg.source = source; 81 | smsg.session = session; 82 | smsg.data = data; 83 | smsg.sz = sz; 84 | 85 | if (Context::push(destination, &smsg)) { 86 | free(data); 87 | skynet_error(NULL, "Drop message from %x to %x (type=%d)(size=%d)", source, destination, type, (int)(sz & HANDLE_MASK)); 88 | return -1; 89 | } 90 | } 91 | return session; 92 | } 93 | 94 | /** 95 | * send message from context to addr, with format of: 96 | * :numberhandle 97 | * .localname 98 | * remote 99 | */ 100 | int send(Context * context, const char * addr , int type, int session, void * data, size_t sz) 101 | { 102 | uint32_t source = context->handle; 103 | uint32_t des = 0; 104 | if (addr[0] == ':') { 105 | des = strtoul(addr+1, NULL, 16); 106 | } else if (addr[0] == '.') { 107 | des = (*Handle::instance())[addr+1]; 108 | if (des == 0) { 109 | free(data); 110 | skynet_error(context, "Drop message to %s", addr); 111 | return session; 112 | } 113 | } else { 114 | _filter_args(context, type, &session, (void **)&data, &sz); 115 | 116 | struct remote_message * rmsg = malloc(sizeof(*rmsg)); 117 | _copy_name(rmsg->destination.name, addr); 118 | rmsg->destination.handle = 0; 119 | rmsg->message = data; 120 | rmsg->sz = sz; 121 | 122 | skynet_harbor_send(rmsg, source, session); 123 | return session; 124 | } 125 | 126 | return send(context, source, des, type, session, data, sz); 127 | } 128 | 129 | private: 130 | /** 131 | * dispatch the message, callback function is called with msg. 132 | */ 133 | static void _dispatch_message(Context *ctx, Message *msg) 134 | { 135 | assert(ctx->init); 136 | CHECKCALLING_BEGIN(ctx) 137 | int type = msg->sz >> HANDLE_REMOTE_SHIFT; 138 | size_t sz = msg->sz & HANDLE_MASK; 139 | if (type == PTYPE_MULTICAST) { 140 | skynet_multicast_dispatch((struct skynet_multicast_message *)msg->data, ctx, 141 | } else { 142 | int reserve = ctx->cb(ctx, ctx->cb_ud, type, msg->session, msg->source, msg->data, sz); 143 | reserve |= _forwarding(ctx, msg); 144 | if (!reserve) { 145 | free(msg->data); 146 | } 147 | } 148 | CHECKCALLING_END(ctx) 149 | } 150 | 151 | /** 152 | * pre-work for sending message. 153 | */ 154 | static void _filter_args(Context * context, int type, int *session, void ** data, size_t * sz) 155 | { 156 | int dontcopy = type & PTYPE_TAG_DONTCOPY; 157 | int allocsession = type & PTYPE_TAG_ALLOCSESSION; 158 | type &= 0xff; 159 | 160 | if (allocsession) { 161 | assert(*session == 0); 162 | *session = context->newsession(); 163 | } 164 | 165 | char * msg; 166 | if (dontcopy || *data == NULL) { 167 | msg = *data; 168 | } else { 169 | msg = malloc(*sz+1); 170 | memcpy(msg, *data, *sz); 171 | msg[*sz] = '\0'; 172 | } 173 | *data = msg; 174 | 175 | assert((*sz & HANDLE_MASK) == *sz); 176 | *sz |= type << HANDLE_REMOTE_SHIFT; 177 | } 178 | 179 | /** 180 | * forward the message if set. 181 | */ 182 | static int _forwarding(Context *ctx, Message *msg) 183 | { 184 | if (ctx->forward) { 185 | uint32_t des = ctx->forward; 186 | ctx->forward = 0; 187 | _send_message(des, msg); 188 | return 1; 189 | } 190 | return 0; 191 | } 192 | 193 | /** 194 | * forward-message sender 195 | */ 196 | static void _send_message(uint32_t des, Message *msg) 197 | { 198 | if (skynet_harbor_message_isremote(des)) { 199 | struct remote_message * rmsg = malloc(sizeof(*rmsg)); 200 | rmsg->destination.handle = des; 201 | rmsg->message = msg->data; 202 | rmsg->sz = msg->sz; 203 | skynet_harbor_send(rmsg, msg->source, msg->session); 204 | } else { 205 | if (Context::push(des, msg)) { 206 | free(msg->data); 207 | skynet_error(NULL, "Drop message from %x forward to %x (size=%d)", msg->source, des, (int)msg->sz); 208 | } 209 | } 210 | } 211 | 212 | 213 | static void _mc(void *ud, uint32_t source, const void * msg, size_t sz) 214 | { 215 | Context * ctx = ud; 216 | int type = sz >> HANDLE_REMOTE_SHIFT; 217 | sz &= HANDLE_MASK; 218 | ctx->cb(ctx, ctx->cb_ud, type, 0, source, msg, sz); 219 | if (ctx->forward) { 220 | uint32_t des = ctx->forward; 221 | ctx->forward = 0; 222 | struct skynet_message message; 223 | message.source = source; 224 | message.session = 0; 225 | message.data = malloc(sz); 226 | memcpy(message.data, msg, sz); 227 | message.sz = sz | (type << HANDLE_REMOTE_SHIFT); 228 | _send_message(des, &message); 229 | } 230 | } 231 | 232 | } 233 | } 234 | #endif // 235 | -------------------------------------------------------------------------------- /include/env.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIBERNET_ENV_H__ 2 | #define __FIBERNET_ENV_H__ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace fibernet 11 | { 12 | class Env 13 | { 14 | private: 15 | int m_lock; 16 | lua_State *L; 17 | static Env * m_instance; 18 | 19 | public: 20 | static Env * instance() 21 | { 22 | if (!m_instance) m_instance = new Env; 23 | return m_instance; 24 | } 25 | 26 | const char * get(const char *key) 27 | { 28 | lock(); 29 | 30 | lua_State *L = E->L; 31 | 32 | lua_getglobal(L, key); 33 | const char * result = lua_tostring(L, -1); 34 | lua_pop(L, 1); 35 | 36 | unlock(); 37 | 38 | return result; 39 | } 40 | 41 | void set(const char *key, const char *value) 42 | { 43 | lock(); 44 | 45 | lua_State *L = E->L; 46 | lua_getglobal(L, key); 47 | assert(lua_isnil(L, -1)); 48 | lua_pop(L,1); 49 | lua_pushstring(L,value); 50 | lua_setglobal(L,key); 51 | 52 | unlock(); 53 | } 54 | 55 | private: 56 | Env(const Env&); 57 | Env& operator= (const Env&); 58 | 59 | Env():m_lock(0) 60 | { 61 | L = luaL_newstate(); 62 | } 63 | 64 | inline void lock() { while (__sync_lock_test_and_set(&m_lock,1)) {} } 65 | inline void unlock() { __sync_lock_release(&m_lock); } 66 | }; 67 | } 68 | 69 | 70 | #endif // 71 | -------------------------------------------------------------------------------- /include/errorlog.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIBERNET_LOG_H__ 2 | #define __FIBERNET_LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define LOG_MESSAGE_SIZE 1024 9 | 10 | namespace fibernet 11 | { 12 | void errorlog(Context * context, const char *msg, ...) 13 | { 14 | static int logger = -1; 15 | if (logger < 0) { 16 | logger = Handle::instance()->get_handle("logger"); 17 | } 18 | if (logger < 0) { 19 | return; 20 | } 21 | 22 | char tmp[LOG_MESSAGE_SIZE]; 23 | 24 | va_list ap; 25 | va_start(ap,msg); 26 | int len = vsnprintf(tmp, LOG_MESSAGE_SIZE, msg, ap); 27 | va_end(ap); 28 | 29 | if (len >= LOG_MESSAGE_SIZE) { 30 | len = LOG_MESSAGE_SIZE - 1; 31 | tmp[len] = '\0'; 32 | } 33 | 34 | Messsage smsg; 35 | if (context == NULL) { 36 | smsg.source = 0; 37 | } else { 38 | smsg.source = context->handle(); 39 | } 40 | smsg.session = 0; 41 | smsg.data = strdup(tmp); 42 | smsg.sz = len | (PTYPE_TEXT << HANDLE_REMOTE_SHIFT); 43 | logger->push(&smsg); 44 | } 45 | } 46 | 47 | #endif // 48 | -------------------------------------------------------------------------------- /include/fibernet.h: -------------------------------------------------------------------------------- 1 | #ifndef FIBERNET_H 2 | #define FIBERNET_H 3 | 4 | #include 5 | #include 6 | 7 | #define PTYPE_TEXT 0 8 | #define PTYPE_RESPONSE 1 9 | #define PTYPE_MULTICAST 2 10 | #define PTYPE_CLIENT 3 11 | #define PTYPE_SYSTEM 4 12 | #define PTYPE_HARBOR 5 13 | #define PTYPE_TAG_DONTCOPY 0x10000 14 | #define PTYPE_TAG_ALLOCSESSION 0x20000 15 | 16 | typedef int (*fibernet_cb)(struct skynet_context * context, void *ud, int type, int session, uint32_t source , const void * msg, size_t sz); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /include/group_mgr.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIBERNET_GROUP_H__ 2 | #define __FIBERNET_GROUP_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "hash_table.h" 9 | 10 | #define DEFAULT_HASHTABLE_SIZE 1024 11 | 12 | namespace fibernet 13 | { 14 | /** 15 | * manages all groups 16 | */ 17 | class GroupManager 18 | { 19 | private: 20 | HashTable m_hash; 21 | int m_lock; 22 | 23 | static GroupManager * m_instance; 24 | 25 | public: 26 | 27 | static GroupManager * instance() 28 | { 29 | if (!m_instance) { 30 | m_instance = new GroupManager(); 31 | } 32 | return m_instance; 33 | } 34 | 35 | /** 36 | * query a group by a handle 37 | */ 38 | uint32_t query(int group_handle) 39 | { 40 | lock(); 41 | 42 | Context * ctx = NULL; 43 | if (m_hash.contains(group_handle)) { 44 | ctx = m_hash[group_handle]; 45 | } else { 46 | ctx = create_group(group_handle); 47 | } 48 | 49 | unlock(); 50 | 51 | return ctx->handle(); 52 | } 53 | 54 | /** 55 | * a context handle enters a group 56 | */ 57 | void enter(int group_handle, uint32_t handle) 58 | { 59 | lock(); 60 | 61 | Context * ctx = NULL; 62 | if (m_hash.contains(group_handle)) { 63 | ctx = m_hash[group_handle]; 64 | } else { 65 | ctx = create_group(group_handle); 66 | } 67 | 68 | unlock(); 69 | 70 | send_command(ctx, "E", handle); 71 | } 72 | 73 | /** 74 | * a context handle leaves a group 75 | */ 76 | void leave(int group_handle, uint32_t handle) 77 | { 78 | lock(); 79 | 80 | if (m_hash.contains(group_handle)) { 81 | Context * ctx = m_hash[group_handle]; 82 | send_command(ctx, "L", handle); 83 | } 84 | 85 | unlock(); 86 | } 87 | 88 | /** 89 | * delete a group 90 | */ 91 | void clear(int group_handle) 92 | { 93 | lock(); 94 | 95 | if (m_hash.contains(group_handle)) { 96 | Context * ctx = m_hash[group_handle]; 97 | char * cmd = malloc(8); 98 | int n = sprintf(cmd, "C"); 99 | Dispatcher::send(ctx, cmd, n+1, 0 , PTYPE_SYSTEM, 0); 100 | m_hash.delete_key(group_handle); 101 | } 102 | 103 | unlock(); 104 | } 105 | 106 | private: 107 | GroupManager(): m_hash(DEFAULT_HASHTABLE_SIZE); 108 | 109 | GroupManager(const GroupManager&); 110 | GroupManager& operator= (const GroupManager&); 111 | 112 | inline void lock() { while (__sync_lock_test_and_set(&m_lock,1)) {} } 113 | inline void unlock() { __sync_lock_release(&m_lock); } 114 | 115 | Context * create_group(struct group * g, int handle) 116 | { 117 | Context * ctx = ContextFactory::create("multicast", NULL); 118 | assert(ctx); 119 | 120 | m_hash.insert(handle, ctx); 121 | return ctx; 122 | } 123 | 124 | void send_command(Context *ctx, const char * cmd, uint32_t node) { 125 | char * tmp = malloc(16); 126 | int n = sprintf(tmp, "%s %x", cmd, node); 127 | Dispatcher::send(ctx, tmp, n+1 , 0, PTYPE_SYSTEM, 0); 128 | } 129 | } 130 | } 131 | 132 | #endif // 133 | -------------------------------------------------------------------------------- /include/handle.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIBERNET_HANDLE_H__ 2 | #define __FIBERNET_HANDLE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "lib/rbtree.h" 11 | #include "rwlock.h" 12 | #include "fibernet.h" 13 | 14 | #define HANDLE_REMOTE_SHIFT 24 15 | 16 | namespace fibernet 17 | { 18 | class Context; 19 | class Handle { 20 | private: 21 | rwlock lock; // read-write lock for rbtree 22 | uint32_t m_harbor; // harbor id 23 | uint32_t handle_index; // for generate handle id 24 | // if we generate one id per second 25 | // it will overflow in 136 years 26 | 27 | alg::RBTree n2h; // name to handle 28 | alg::RBTree h2n; // handle to name 29 | 30 | alg::RBTree h2c; // handle to context 31 | 32 | static Handle * m_instance; 33 | private: 34 | 35 | Handle(const Handle&); 36 | Handle& operator= (const Handle&); 37 | 38 | Handle(int harbor):handle_index(1) 39 | { 40 | // reserve 0 for system 41 | m_harbor = (uint32_t) (harbor & 0xff) << HANDLE_REMOTE_SHIFT; 42 | } 43 | 44 | public: 45 | 46 | static void create_instance(int harbor) 47 | { 48 | if (!m_instance) { 49 | m_instance = new Handle(harbor); 50 | } 51 | } 52 | 53 | static Handle * instance() { return m_instance; } 54 | 55 | /** 56 | * register the context, return the handle. 57 | */ 58 | uint32_t reg(Context *ctx); 59 | 60 | /** 61 | * name a handle 62 | */ 63 | bool reg_name(uint32_t handle, const char *name) 64 | { 65 | std::string tmp = name; 66 | bool ret = false; 67 | 68 | lock.wlock(); 69 | // make sure handle exists 70 | 71 | if (h2c.contains(handle) && !n2h.contains(tmp)) { 72 | insert_name(name, handle); 73 | ret = true; 74 | } 75 | 76 | lock.wunlock(); 77 | 78 | return ret; 79 | } 80 | 81 | 82 | /** 83 | * retire a handle 84 | */ 85 | void retire(uint32_t handle); 86 | 87 | void retireall() 88 | { 89 | uint32_t i; 90 | Context * ctx; 91 | 92 | for (i=1;i 5 | #include 6 | 7 | #define GLOBALNAME_LENGTH 16 8 | #define REMOTE_MAX 256 9 | 10 | // reserve high 8 bits for remote id 11 | #define HANDLE_MASK 0xffffff 12 | #define HANDLE_REMOTE_SHIFT 24 13 | 14 | namespace fibernet 15 | { 16 | struct remote_name { 17 | char name[GLOBALNAME_LENGTH]; 18 | uint32_t handle; 19 | }; 20 | 21 | struct remote_message { 22 | struct remote_name destination; 23 | const void * message; 24 | size_t sz; 25 | }; 26 | 27 | class Context; 28 | class Harbor 29 | { 30 | private: 31 | Context * REMOTE; 32 | uint32_t HARBOR; 33 | 34 | public: 35 | Harbor(int harbor): HARBOR(harbor< 6 | * _| 7 | * 8 | * 2-DIMENSIONAL ARRAY 9 | * 10 | * Simulated by 1-dimension array. 11 | ******************************************************************************/ 12 | 13 | #ifndef __2D_ARRAY_H__ 14 | #define __2D_ARRAY_H__ 15 | #include 16 | #include 17 | 18 | namespace alg 19 | { 20 | /** 21 | * 2D Array definition 22 | */ 23 | template 24 | class Array2D 25 | { 26 | private: 27 | uint32_t NR; // num of rows 28 | uint32_t NC; // num of columns 29 | T * m_data; // the place where the array resides. 30 | 31 | public: 32 | /** 33 | * construct an array of size [nrow,col] 34 | */ 35 | Array2D(uint32_t nrow, uint32_t ncol) { 36 | NR = nrow; 37 | NC = ncol; 38 | m_data = new T[nrow*ncol]; 39 | } 40 | 41 | /** 42 | * destructor 43 | */ 44 | ~Array2D() { 45 | delete [] m_data; 46 | } 47 | 48 | private: 49 | Array2D(const Array2D&); 50 | Array2D& operator=(const Array2D&); 51 | 52 | public: 53 | 54 | /** 55 | * return number of rows of this array 56 | */ 57 | inline const uint32_t row() const { return NR; } 58 | /** 59 | * return number of columns of this array 60 | */ 61 | inline const uint32_t col() const { return NC; } 62 | 63 | /** 64 | * return the value by the given (row, col); 65 | */ 66 | inline T& operator() (int row, int col) { return this->m_data[row*NC + col]; } 67 | const inline T& operator() (int row, int col) const { return this->m_data[row*NC + col]; } 68 | 69 | /** 70 | * clear the array by a given value 71 | */ 72 | void clear(const T & value) 73 | { 74 | for(uint32_t i=0; i 6 | * _| 7 | * 8 | * A* ALGORITHM 9 | * 10 | * Features: 11 | * In computer science, A* (pronounced "A star" ,is a computer algorithm 12 | * that is widely used in pathfinding and graph traversal, the process of 13 | * plotting an efficiently traversable path between points, called nodes. Noted 14 | * for its performance and accuracy, it enjoys widespread use. (However, in 15 | * practical travel-routing systems, it is generally outperformed by algorithms 16 | * which can pre-process the graph to attain better performance.[1]) 17 | * 18 | * http://en.wikipedia.org/wiki/A*_search_algorithm 19 | * 20 | ******************************************************************************/ 21 | 22 | #ifndef __ASTAR_H__ 23 | #define __ASTAR_H__ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "heap.h" 30 | #include "hash_table.h" 31 | #include "2darray.h" 32 | 33 | namespace alg 34 | { 35 | class AStar 36 | { 37 | public: 38 | /** 39 | * A-Star algorithm result; 40 | */ 41 | struct AStarResult { 42 | int * path; // the path format: 43 | // [X1Y1X2Y2X3Y3.....XnYnX1Y1] 44 | // interleaving X,Y coordinate 45 | int num_nodes; 46 | ~AStarResult() 47 | { 48 | delete [] path; 49 | path = NULL; 50 | } 51 | }; 52 | 53 | static const unsigned char WALL = 0xFF; 54 | static const float SQRT2 = 1.414213562373095; 55 | 56 | private: 57 | const Array2D & m_grid; 58 | // The set of nodes already evaluated. 59 | Array2D m_closedset; 60 | // Cost from start along best known path. 61 | Array2D g_score; 62 | // Estimated total cost from start to goal through y. 63 | Array2D f_score; 64 | public: 65 | AStar(const Array2D & grid) : 66 | m_grid(grid), 67 | m_closedset(grid.row(),grid.col()), 68 | g_score(grid.row(),grid.col()), 69 | f_score(grid.row(),grid.col()) { } 70 | 71 | /** 72 | * the A* algorithm 73 | * search a path from (x1,y1) to (x2,y2) 74 | * a integer representing path is returned, you should delete it after. 75 | */ 76 | AStarResult * run(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2) 77 | { 78 | uint32_t nrow = m_grid.row(); 79 | uint32_t ncol = m_grid.col(); 80 | m_closedset.clear(false); 81 | 82 | // the set of tentavie nodes to be evaluated, 83 | // initialy containing the start node 84 | // encoding [x,y] to [x*ncol + y] 85 | // using binary heap ... 86 | Heap openset(nrow*ncol); 87 | openset.insert(0, x1*ncol+y1); 88 | 89 | // The map of navigated nodes. 90 | HashTable came_from(nrow*ncol); 91 | 92 | g_score(x1,y1) = 0.0f; 93 | f_score(x1,y1) = g_score(x1,y1) + estimate(x1,y1,x2,y2); 94 | 95 | AStarResult * as = new AStarResult; 96 | as->path = NULL; 97 | as->num_nodes = 0; 98 | 99 | while(!openset.is_empty()) { 100 | uint32_t value = openset.min_value(); 101 | int cx = value/ncol; 102 | int cy = value%ncol; 103 | 104 | if(cx == (int)x2 && cy==(int)y2) { // we reached (x2,y2) 105 | // reconstruct path & return 106 | uint32_t tmp = x2*ncol+y2; 107 | while((tmp=came_from[tmp]) != x1*ncol+y1) { 108 | as->num_nodes++; 109 | } 110 | 111 | as->path = new int[2*as->num_nodes]; 112 | 113 | tmp = x2*ncol+y2; 114 | int idx=0; 115 | while((tmp=came_from[tmp]) != x1*ncol+y1) { 116 | as->path[idx++] = tmp/ncol; 117 | as->path[idx++] = tmp%ncol; 118 | } 119 | return as; 120 | } 121 | 122 | openset.delete_min(); 123 | m_closedset(cx, cy) = true; 124 | 125 | // for each neighbor 126 | int nx, ny; 127 | for(nx=cx-1;nx<=cx+1;nx++) { 128 | if (nx<0 || nx>=(int)ncol) continue; 129 | for(ny=cy-1;ny<=cy+1;ny++) { 130 | if (ny<0 || ny>=(int)nrow) continue; 131 | 132 | // except the wall; 133 | if(m_grid(nx,ny) == WALL) continue; 134 | // except the cur itself 135 | if(nx == cx && ny==cy) continue; 136 | // if neighbour in the closed set 137 | if(m_closedset(nx,ny)) continue; 138 | 139 | float tentative = g_score(cx,cy) + SQRT2; 140 | 141 | // if neighbour not in the openset or dist < g_score[neighbour] 142 | if (!openset.contains(nx*ncol+ny) || tentative < g_score(nx,ny)) { 143 | came_from[nx*ncol+ny] = cx*ncol+cy; // record path 144 | g_score(nx,ny) = tentative; 145 | f_score(nx,ny) = tentative + estimate(nx,ny,x2,y2); 146 | if (!openset.contains(nx*ncol+ny)) { 147 | openset.insert(f_score(nx,ny), nx*ncol+ny); 148 | } 149 | } 150 | } 151 | } 152 | } 153 | return as; 154 | } 155 | private: 156 | inline float estimate(int x1, int y1, int x2, int y2) const 157 | { 158 | return sqrtf((x2-x1) * (x2-x1) + (y2-y1)*(y2-y1)); 159 | } 160 | }; 161 | 162 | } 163 | 164 | #endif // 165 | -------------------------------------------------------------------------------- /include/lib/bellman_ford.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * BELLMAN-FORD ALGORITHM 9 | * 10 | * The Bellman–Ford algorithm computes single-source shortest paths in a 11 | * weighted digraph. For graphs with only non-negative edge weights, the faster 12 | * Dijkstra's algorithm also solves the problem. Thus, Bellman–Ford is used 13 | * primarily for graphs with negative edge weights. The algorithm is named after 14 | * its developers, Richard Bellman and Lester Ford, Jr. 15 | * 16 | * procedure BellmanFord(list vertices, list edges, vertex source) 17 | * // This implementation takes in a graph, represented as lists of vertices 18 | * // and edges, and modifies the vertices so that their distance and 19 | * // predecessor attributes store the shortest paths. 20 | * 21 | * // Step 1: initialize graph 22 | * for each vertex v in vertices: 23 | * if v is source then v.distance := 0 24 | * else v.distance := infinity 25 | * v.predecessor := null 26 | * 27 | * // Step 2: relax edges repeatedly 28 | * for i from 1 to size(vertices)-1: 29 | * for each edge uv in edges: // uv is the edge from u to v 30 | * u := uv.source 31 | * v := uv.destination 32 | * if u.distance + uv.weight < v.distance: 33 | * v.distance := u.distance + uv.weight 34 | * v.predecessor := u 35 | * 36 | * // Step 3: check for negative-weight cycles 37 | * for each edge uv in edges: 38 | * u := uv.source 39 | * v := uv.destination 40 | * if u.distance + uv.weight < v.distance: 41 | * error "Graph contains a negative-weight cycle" 42 | * 43 | * http://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm 44 | * 45 | ******************************************************************************/ 46 | 47 | #ifndef __BELLMAN_FORD_H__ 48 | #define __BELLMAN_FORD_H__ 49 | 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | #include "directed_graph.h" 57 | #include "hash_table.h" 58 | 59 | // define UNDEFINED previous vertex. 60 | #define UNDEFINED -1 61 | 62 | namespace alg 63 | { 64 | 65 | class BellmanFord 66 | { 67 | private: 68 | HashTable dist; // hash table for distance. 69 | bool has_neg_cycle; // negative weighted cycle mark. 70 | const Graph & g; 71 | public: 72 | BellmanFord(const Graph & graph): 73 | dist(graph.vertex_count()),g(graph) 74 | { } 75 | 76 | /** 77 | * Bellman-Ford algorithm 78 | */ 79 | HashTable * run(uint32_t source) 80 | { 81 | // hash table for previous vertex 82 | HashTable * previous = new HashTable(g.vertex_count()); 83 | // source vertex 84 | dist[source] = 0; 85 | 86 | // other vertices 87 | Graph::Adjacent * a; 88 | list_for_each_entry(a, &g.list(), a_node){ 89 | if (source != a->v.id) { 90 | dist[a->v.id] = INT_MAX; 91 | } 92 | (*previous)[a->v.id] = UNDEFINED; 93 | } 94 | 95 | has_neg_cycle = false; // negative cycle mark set to 'false'. 96 | 97 | // relax edges repeatedly 98 | Graph::Adjacent * u; 99 | for (uint32_t i=0;iv.id]; 102 | 103 | Graph::Vertex * v; 104 | list_for_each_entry(v, &u->v_head, v_node){ 105 | int32_t dist_v = dist[v->id]; 106 | 107 | if (dist_u + v->weight < dist_v) { 108 | dist[v->id] = dist_u + v->weight; 109 | (*previous)[v->id] = u->v.id; 110 | } 111 | } 112 | } 113 | } 114 | 115 | // check for negative-weight cycles 116 | list_for_each_entry(u, &g.list(), a_node) { 117 | int32_t dist_u = dist[u->v.id]; 118 | 119 | Graph::Vertex * v; 120 | list_for_each_entry(v, &u->v_head, v_node){ 121 | int32_t dist_v = dist[v->id]; 122 | 123 | if (dist_u + v->weight < dist_v) { 124 | has_neg_cycle = true; // graph contains a negative-weight cycle 125 | return previous; 126 | } 127 | } 128 | } 129 | 130 | return previous; 131 | } 132 | 133 | inline bool has_negative_cycle() { return has_neg_cycle; } 134 | }; 135 | } 136 | 137 | #endif // 138 | -------------------------------------------------------------------------------- /include/lib/binary_search_tree.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * BINARY SEARCH TREE 9 | * 10 | * Features: 11 | * 1. Expected search time is O(nlogn). 12 | * 2. Data should be !!!SHUFFLED!!! first before tree creation. 13 | * 3. First initialize the value of the root (pointer to the 14 | * structure treeNode) with NULL. eg: 15 | * treeNode *root = NULL 16 | * 17 | * http://en.wikipedia.org/wiki/Binary_search_tree 18 | * 19 | ******************************************************************************/ 20 | 21 | #ifndef __BINARY_SEARCH_TREE_H__ 22 | #define __BINARY_SEARCH_TREE_H__ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace alg 29 | { 30 | template 31 | class BST 32 | { 33 | private: 34 | /** 35 | * binary search tree definiton. 36 | */ 37 | struct treeNode 38 | { 39 | KeyT key; // key 40 | ValueT value; // data 41 | treeNode *left; // left child 42 | treeNode *right; // right child 43 | }; 44 | 45 | class BSTException: public std::exception 46 | { 47 | public: 48 | virtual const char * what() const throw() 49 | { 50 | return "key does not exist"; 51 | } 52 | }; 53 | 54 | private: 55 | treeNode * m_root; 56 | const BSTException error; 57 | 58 | public: 59 | BST():m_root(NULL){}; 60 | 61 | ~BST() 62 | { 63 | destruct(m_root); 64 | } 65 | 66 | ValueT operator[] (const KeyT & key) 67 | { 68 | if (m_root == NULL) throw error; 69 | treeNode * tmp = m_root; 70 | 71 | while(true) { 72 | if (key == tmp->key) return tmp->value; 73 | else if(key < tmp->key) { 74 | if (tmp->left == NULL) throw error; 75 | tmp = tmp->left; 76 | } else { 77 | if (tmp->right == NULL) throw error; 78 | tmp = tmp->right; 79 | } 80 | } 81 | } 82 | 83 | /** 84 | * test whether the key is in the tree 85 | */ 86 | bool contains(const KeyT & key) 87 | { 88 | if (m_root == NULL) return false; 89 | treeNode * tmp = m_root; 90 | 91 | while(true) { 92 | if (key == tmp->key) return true; 93 | else if(key < tmp->key) { 94 | if (tmp->left == NULL) return false; 95 | tmp = tmp->left; 96 | } else { 97 | if (tmp->right == NULL) return false; 98 | tmp = tmp->right; 99 | } 100 | } 101 | } 102 | 103 | /** 104 | * insert a new data into the binary search tree. 105 | */ 106 | bool insert(const KeyT & key, const ValueT & value) 107 | { 108 | treeNode *n = new treeNode; 109 | n->key = key; 110 | n->value = value; 111 | n->left = n->right = NULL; 112 | 113 | if (m_root == NULL){ 114 | m_root = n; 115 | return true; 116 | } 117 | treeNode * tmp = m_root; 118 | 119 | while(true) { 120 | if (key == tmp->key) { // already inserted 121 | delete n; 122 | return false; 123 | } 124 | else if(key < tmp->key) { 125 | if (tmp->left == NULL) { 126 | tmp->left = n; 127 | return true; 128 | } else tmp = tmp->left; 129 | } else { 130 | if (tmp->right == NULL) { 131 | tmp->right = n; 132 | return true; 133 | } else tmp = tmp->right; 134 | } 135 | } 136 | } 137 | private: 138 | void destruct(treeNode *n) 139 | { 140 | if (n==NULL) return; 141 | destruct(n->left); 142 | destruct(n->right); 143 | delete n; 144 | } 145 | 146 | private: 147 | BST(const BST&); 148 | BST& operator=(const BST&); 149 | }; 150 | } 151 | 152 | #endif // 153 | -------------------------------------------------------------------------------- /include/lib/bitset.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * BIT-SET 9 | * 10 | * a bit-set data structure 11 | * 12 | ******************************************************************************/ 13 | 14 | #ifndef __BIT_SET_H__ 15 | #define __BIT_SET_H__ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | namespace alg 23 | { 24 | /** 25 | * definition of bitset class 26 | */ 27 | class BitSet 28 | { 29 | private: 30 | uint32_t m_size; //size in bits 31 | uint32_t m_bytes; // size in bytes 32 | unsigned char * m_bits; // the bits 33 | 34 | public: 35 | /** 36 | * construct BitSet by a give number of bits 37 | */ 38 | BitSet(uint32_t num_bits) 39 | { 40 | // round up 41 | m_bytes = num_bits/8+1; 42 | m_size = m_bytes * 8; 43 | m_bits = new unsigned char[m_bytes]; 44 | memset(m_bits, 0, m_bytes); 45 | } 46 | 47 | /** 48 | * safely free 49 | */ 50 | ~BitSet() 51 | { 52 | delete [] m_bits; 53 | } 54 | 55 | private: 56 | BitSet(const BitSet&); 57 | BitSet& operator=(const BitSet&); 58 | 59 | public: 60 | 61 | /** 62 | * set 1 to position [bit] 63 | */ 64 | inline void set(uint32_t bit) 65 | { 66 | if (bit>=m_size) return; 67 | 68 | uint32_t n = bit/8; 69 | uint32_t off = bit%8; 70 | 71 | m_bits[n] |= 128U>>off; 72 | } 73 | 74 | /** 75 | * set 0 to position [bit] 76 | */ 77 | inline void unset(uint32_t bit) 78 | { 79 | if (bit>=m_size) return; 80 | 81 | uint32_t n = bit/8; 82 | uint32_t off = bit%8; 83 | 84 | m_bits[n] &= ~(128U>>off); 85 | } 86 | 87 | /** 88 | * test a bit , true if set, false if not. 89 | */ 90 | inline bool test(uint32_t bit) 91 | { 92 | if (bit>=m_size) return false; 93 | 94 | uint32_t n = bit/8; 95 | uint32_t off = bit%8; 96 | 97 | if (m_bits[n] & (128U>>off))return true; 98 | return false; 99 | } 100 | 101 | }; 102 | } 103 | 104 | #endif // 105 | -------------------------------------------------------------------------------- /include/lib/bloom_filter.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * BLOOM FILTER 9 | * 10 | * Features: 11 | * A Bloom filter with 1% error and an optimal value of k, in contrast, 12 | * requires only about 9.6 bits per element — regardless of the size of the 13 | * elements. This advantage comes partly from its compactness, inherited from 14 | * arrays, and partly from its probabilistic nature. If a 1% false-positive rate 15 | * seems too high, adding about 4.8 bits per element decreases it by ten times. 16 | * 17 | * http://en.wikipedia.org/wiki/Bloom_filter 18 | * 19 | ******************************************************************************/ 20 | 21 | #ifndef __BLOOM_FILTER_H__ 22 | #define __BLOOM_FILTER_H__ 23 | 24 | #include 25 | #include 26 | #include 27 | #include "universal_hash.h" 28 | #include "hash_string.h" 29 | #include "bitset.h" 30 | #include "sha1.h" 31 | 32 | namespace alg 33 | { 34 | /** 35 | * definiton of bloom filter structure 36 | */ 37 | template 38 | class BloomFilter { 39 | private: 40 | uint32_t m_bits; // num of bits 41 | uint32_t m_probset; // total elements 42 | BitSet m_bitset; // the bit set structure. 43 | struct UHash m_hash[K]; // universal hash parameters 44 | public: 45 | /** 46 | * check false positive rate here, for setting up: 47 | * http://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html 48 | * Examples: 49 | * Table 3: False positive rate under various m/n and k combinations. 50 | m/n k(opt) k=1 k=2 k=3 k=4 k=5 k=6 k=7 k=8 51 | 2 1.39 0.393 0.400 52 | 3 2.08 0.283 0.237 0.253 53 | 4 2.77 0.221 0.155 0.147 0.160 54 | 5 3.46 0.181 0.109 0.092 0.092 0.101 55 | 6 4.16 0.154 0.0804 0.0609 0.0561 0.0578 0.0638 56 | 7 4.85 0.133 0.0618 0.0423 0.0359 0.0347 0.0364 57 | 8 5.55 0.118 0.0489 0.0306 0.024 0.0217 0.0216 0.0229 58 | 9 6.24 0.105 0.0397 0.0228 0.0166 0.0141 0.0133 0.0135 0.0145 59 | 10 6.93 0.0952 0.0329 0.0174 0.0118 0.00943 0.00844 0.00819 0.00846 60 | 11 7.62 0.0869 0.0276 0.0136 0.00864 0.0065 0.00552 0.00513 0.00509 61 | 12 8.32 0.08 0.0236 0.0108 0.00646 0.00459 0.00371 0.00329 0.00314 62 | 13 9.01 0.074 0.0203 0.00875 0.00492 0.00332 0.00255 0.00217 0.00199 63 | 14 9.7 0.0689 0.0177 0.00718 0.00381 0.00244 0.00179 0.00146 0.00129 64 | 15 10.4 0.0645 0.0156 0.00596 0.003 0.00183 0.00128 0.001 0.000852 65 | 16 11.1 0.0606 0.0138 0.005 0.00239 0.00139 0.000935 0.000702 0.000574 66 | 17 11.8 0.0571 0.0123 0.00423 0.00193 0.00107 0.000692 0.000499 0.000394 67 | 18 12.5 0.054 0.0111 0.00362 0.00158 0.000839 0.000519 0.00036 0.000275 68 | 19 13.2 0.0513 0.00998 0.00312 0.0013 0.000663 0.000394 0.000264 0.000194 69 | 20 13.9 0.0488 0.00906 0.0027 0.00108 0.00053 0.000303 0.000196 0.00014 70 | 21 14.6 0.0465 0.00825 0.00236 0.000905 0.000427 0.000236 0.000147 0.000101 71 | 72 | * as we can see: 73 | * to reach 1% positive rate, you can set k=8, m 10 times larger than n. 74 | * to reach 0.1% positive rate, set k=8, m 15 times larger than n. 75 | * 76 | * k-->num of hash functions 77 | * m--> bit set size 78 | * n--> problem set size 79 | */ 80 | BloomFilter(uint32_t m, uint32_t n):m_bitset(m) 81 | { 82 | assert(m>n); 83 | m_bits=m; 84 | m_probset=n; 85 | 86 | for(uint32_t i=0;i 6 | * _| 7 | * 8 | * DIJKSTRA ALGORITHM 9 | * 10 | * Features: 11 | * 12 | * Dijkstra's algorithm, conceived by Dutch computer scientist Edsger Dijkstra 13 | * in 1956 and published in 1959,[1][2] is a graph search algorithm that 14 | * solves the single-source shortest path problem for a graph with nonnegative 15 | * edge path costs, producing a shortest path tree. This algorithm is often 16 | * used in routing and as a subroutine in other graph algorithms. 17 | * 18 | * http://en.wikipedia.org/wiki/Dijkstra's_algorithm 19 | * 20 | ******************************************************************************/ 21 | 22 | #ifndef __DIJKSTRA_H__ 23 | #define __DIJKSTRA_H__ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "heap.h" 32 | #include "directed_graph.h" 33 | #include "stack.h" 34 | #include "hash_table.h" 35 | 36 | namespace alg 37 | { 38 | /** 39 | * the dijkstra algorithm workspace 40 | */ 41 | class Dijkstra { 42 | private: 43 | const Graph & g; 44 | Heap Q; // a binary heap 45 | HashTable dist; // distance hash table 46 | public: 47 | static const int UNDEFINED = -1; 48 | /** 49 | * init dijkstra workspace 50 | */ 51 | Dijkstra(const struct Graph & graph):g(graph), 52 | Q(g.vertex_count()), 53 | dist(g.vertex_count()) {} 54 | 55 | // run dijkstra algorithm, and return the previous table 56 | HashTable * run(uint32_t src_id) 57 | { 58 | // previous vertex hash table 59 | HashTable * previous = new HashTable(g.vertex_count()); 60 | 61 | Q.clear(); 62 | dist.clear(); 63 | 64 | // source 65 | Graph::Adjacent * source = g[src_id]; 66 | Q.insert(0, source->v.id); // weight->id binary heap 67 | dist[source->v.id] = 0; 68 | 69 | // other vertices 70 | Graph::Adjacent * a; 71 | list_for_each_entry(a, &g.list(), a_node){ 72 | if (a->v.id != source->v.id) { 73 | Q.insert(INT_MAX, a->v.id); 74 | // set inital distance to INT_MAX 75 | dist[a->v.id] = INT_MAX; 76 | // set initial value to UNDEFINED 77 | } 78 | (*previous)[a->v.id] = UNDEFINED; 79 | } 80 | 81 | while(!Q.is_empty()) { // The main loop 82 | Graph::Adjacent * u = g[Q.min_value()]; 83 | int dist_u = Q.min_key(); 84 | Q.delete_min(); 85 | 86 | if (dist_u == INT_MAX) { 87 | break; 88 | } 89 | 90 | Graph::Vertex * v; 91 | list_for_each_entry(v, &u->v_head, v_node){ 92 | uint32_t alt = dist_u + v->weight; 93 | uint32_t dist_v = dist[v->id]; 94 | if (alt < dist_v) { 95 | dist[v->id] = alt; 96 | Q.decrease_key(v->id, alt); 97 | (*previous)[v->id] = u->v.id; 98 | } 99 | } 100 | } 101 | 102 | return previous; 103 | }; 104 | }; 105 | } 106 | 107 | #endif // 108 | -------------------------------------------------------------------------------- /include/lib/directed_graph.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * DIRECTED GRAPH 9 | * 10 | * Features: 11 | * 1. Adjacency List Implementation 12 | * 13 | * http://en.wikipedia.org/wiki/Directed_graph 14 | * 15 | ******************************************************************************/ 16 | 17 | #ifndef __DIRECTED_GRAPH_H__ 18 | #define __DIRECTED_GRAPH_H__ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "graph_defs.h" 27 | #include "double_linked_list.h" 28 | 29 | namespace alg 30 | { 31 | class DirectedGraph:public Graph 32 | { 33 | private: 34 | /** 35 | * delete a vertex from adjacent lists 36 | */ 37 | void delete_me(uint32_t id) 38 | { 39 | // delete every connection, iterator through every adjacent list 40 | Adjacent * adj; 41 | list_for_each_entry(adj, &a_head, a_node){ 42 | if (adj->v.id != id) { 43 | if((*adj)[id]!=NULL) { // if connected to id 44 | adj->delete_vertex(id); 45 | num_edges--; 46 | } 47 | } 48 | } 49 | } 50 | public: 51 | /** 52 | * delete a vertex with specified id 53 | */ 54 | void delete_vertex(uint32_t id) 55 | { 56 | Adjacent * a = (*this)[id]; 57 | if (a==NULL) return; 58 | delete_me(id); 59 | // delete adjacent list itself. 60 | num_vertex--; 61 | num_edges -= a->num_neigh; 62 | list_del(&a->a_node); 63 | delete a; 64 | } 65 | 66 | /** 67 | * create a new vertex and add to the graph, with specified id. 68 | */ 69 | bool add_vertex(uint32_t id) 70 | { 71 | if ((*this)[id]!=NULL) return false; 72 | 73 | // new empty adjacent list 74 | Adjacent * a = new Adjacent(id); 75 | list_add_tail(&a->a_node, &a_head); 76 | num_vertex++; 77 | 78 | return true; 79 | } 80 | 81 | /** 82 | * add an edge for x -> y 83 | */ 84 | bool add_edge(uint32_t x, uint32_t y, int32_t weight) 85 | { 86 | struct Adjacent * a1 = (*this)[x]; 87 | struct Adjacent * a2 = (*this)[y]; 88 | 89 | // make sure both vertex exists & not connected from x->y 90 | if (a1==NULL || a2==NULL) return false; 91 | if (is_adjacent(a1, a2)) return false; 92 | 93 | // create new vertex & add to adjacent list 94 | Vertex * n = new Vertex(y); 95 | n->weight = weight; 96 | list_add_tail(&n->v_node, &a1->v_head); 97 | 98 | num_edges++; 99 | a1->num_neigh++; 100 | 101 | return true; 102 | } 103 | 104 | /** 105 | * delete an edge for x -> y 106 | */ 107 | void delete_edge(uint32_t x, uint32_t y) 108 | { 109 | struct Adjacent * a1 = (*this)[x]; 110 | struct Adjacent * a2 = (*this)[y]; 111 | if (a1==NULL || a2==NULL) return ; 112 | if (!is_adjacent(a1, a2)) return ; 113 | 114 | Vertex * v, *n; 115 | // find y in adjacent list of x 116 | list_for_each_entry_safe(v, n, &a1->v_head, v_node){ 117 | if (v->id == y) { 118 | list_del(&v->v_node); 119 | delete v; 120 | num_edges--; 121 | a1->num_neigh--; 122 | } 123 | } 124 | } 125 | 126 | }; 127 | } 128 | 129 | #endif // 130 | -------------------------------------------------------------------------------- /include/lib/dos_tree.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * DYNAMIC ORDER STATISTIC 9 | * 10 | * Features: 11 | * 1. based on red-black tree 12 | * 2. O(logn) lookup time 13 | * 3. Select the i-th largest element 14 | * 15 | * http://en.wikipedia.org/wiki/Order_statistic 16 | * 17 | ******************************************************************************/ 18 | 19 | #ifndef __DOS_TREE_H__ 20 | #define __DOS_TREE_H__ 21 | 22 | #include 23 | #include 24 | #include 25 | #include "generic.h" 26 | #include "stack.h" 27 | #include "double_linked_list.h" 28 | #include "rbtree.h" 29 | 30 | namespace alg 31 | { 32 | class DosTree:public RBTreeAbstract 33 | { 34 | public: 35 | /** 36 | * dynamic order stat node structure definition 37 | */ 38 | typedef struct dostree_node_t : public rbtree_node_t { 39 | int key; // the key 40 | int size; // the size of this subtree 41 | } *dostree_node; 42 | 43 | #define DOSNODE(rbnode) static_cast(rbnode) 44 | #define DOSNODE_SIZE(rbnode) (rbnode?DOSNODE(rbnode)->size:0) 45 | 46 | public: 47 | DosTree() { } 48 | private: 49 | DosTree(const DosTree&); 50 | DosTree& operator=(const DosTree&); 51 | public: 52 | 53 | dostree_node index(int index) 54 | { 55 | return lookup_node(get_root(),index); 56 | } 57 | 58 | /** 59 | * dostree_insert 60 | * insert a new key into the dos tree 61 | */ 62 | void insert(int key) 63 | { 64 | dostree_node inserted_node = new_node(key, RED, NULL, NULL); 65 | 66 | if (get_root() == NULL) { 67 | set_root(inserted_node); 68 | } 69 | else { 70 | rbtree_node n = DOSNODE(get_root()); 71 | while (1) { 72 | // incr 1 for each node on the path traversed from the root 73 | DOSNODE(n)->size+=1; 74 | if (key < DOSNODE(n)->key) { 75 | if (n->left == NULL) { 76 | n->left = inserted_node; 77 | break; 78 | } else { 79 | n = n->left; 80 | } 81 | } else { 82 | if (n->right == NULL) { 83 | n->right = inserted_node; 84 | break; 85 | } else { 86 | n = n->right; 87 | } 88 | } 89 | } 90 | inserted_node->parent = n; 91 | } 92 | 93 | // fix red-black properties 94 | insert_case1(inserted_node); 95 | } 96 | 97 | /** 98 | * delete the key in the red-black tree 99 | */ 100 | void delete_key(dostree_node n) 101 | { 102 | rbtree_node child; 103 | 104 | // phase 1. fix up size 105 | fixup_size(n); 106 | 107 | // phase 2. handle red-black properties, and deletion work. 108 | if (n->left != NULL && n->right != NULL) { 109 | /* Copy key/value from predecessor and then delete it instead */ 110 | dostree_node pred = DOSNODE(maximum_node(n->left)); 111 | DOSNODE(n)->key = DOSNODE(pred)->key; 112 | DOSNODE(n)->size = DOSNODE(pred)->size; 113 | n = pred; 114 | } 115 | 116 | assert(n->left == NULL || n->right == NULL); 117 | child = n->right == NULL ? n->left : n->right; 118 | if (node_color(n) == BLACK) { 119 | n->color = node_color(child); 120 | delete_case1(n); 121 | } 122 | replace_node(n, child); 123 | if (n->parent == NULL && child != NULL) 124 | child->color = BLACK; 125 | 126 | delete (DOSNODE(n)); 127 | } 128 | 129 | void print() { 130 | print_helper(get_root(), 0); 131 | puts(""); 132 | } 133 | 134 | void print_helper(rbtree_node n, int indent) { 135 | int i; 136 | if (n == NULL) { 137 | fputs("", stdout); 138 | return; 139 | } 140 | if (n->right != NULL) { 141 | print_helper(n->right, indent + INDENT_STEP); 142 | } 143 | for(i=0; icolor == BLACK) 146 | printf("[key:%d size:%d]\n", DOSNODE(n)->key,DOSNODE(n)->size); 147 | else 148 | printf("*[key:%d size:%d]\n", DOSNODE(n)->key, DOSNODE(n)->size); 149 | if (n->left != NULL) { 150 | print_helper(n->left, indent + INDENT_STEP); 151 | } 152 | } 153 | private: 154 | /** 155 | * dostree_lookup 156 | * 157 | * select the i-th largest element 158 | */ 159 | dostree_node lookup_node(rbtree_node n, int i) 160 | { 161 | if (n == NULL) return NULL; // beware of NULL pointer 162 | int size = DOSNODE_SIZE(n->left) + 1; 163 | 164 | if(i == size) return DOSNODE(n); 165 | if(i < size ) return lookup_node(n->left, i); 166 | else return lookup_node(n->right, i-size); 167 | } 168 | /** 169 | * left/right rotation call back function 170 | */ 171 | void rotate_left_callback(rbtree_node n, rbtree_node parent) 172 | { 173 | DOSNODE(parent)->size = DOSNODE_SIZE(n); 174 | DOSNODE(n)->size = DOSNODE_SIZE(n->left) + DOSNODE_SIZE(n->right) + 1; 175 | } 176 | 177 | void rotate_right_callback(rbtree_node n, rbtree_node parent) 178 | { 179 | rotate_left_callback(n,parent); 180 | } 181 | 182 | /** 183 | * fix procedure caused by deletion 184 | */ 185 | void fixup_size(rbtree_node n) 186 | { 187 | // fix up to the root 188 | n = n->parent; 189 | while(n != NULL) { 190 | DOSNODE(n)->size -= 1; 191 | n = n->parent; 192 | } 193 | } 194 | 195 | static inline dostree_node 196 | new_node(int key, color rbtree_node_color, rbtree_node left, rbtree_node right) 197 | { 198 | dostree_node result =new dostree_node_t; 199 | result->key = key; 200 | result->size = 1; 201 | result->color = rbtree_node_color; 202 | result->left = NULL; 203 | result->right = NULL; 204 | if(left !=NULL) left->parent = result; 205 | if(right!=NULL) right->parent = result; 206 | result->parent = NULL; 207 | return result; 208 | } 209 | 210 | }; 211 | } 212 | 213 | #endif 214 | -------------------------------------------------------------------------------- /include/lib/double_linked_list.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * DOUBLE LINKED-LIST FROM LINUX KERNEL 9 | * 10 | * Features: 11 | * 1. clean 12 | * 2. data independent 13 | * 3. data structure contains next & prev pointer(in list_head struct), 14 | * not like linked-list contains data 15 | * 16 | * http://en.wikipedia.org/wiki/Double_linked_list 17 | ******************************************************************************/ 18 | 19 | #ifndef __DOUBLE_LINKED_LIST_H__ 20 | #define __DOUBLE_LINKED_LIST_H__ 21 | 22 | struct list_head { 23 | struct list_head *next, *prev; 24 | }; 25 | 26 | #define LIST_HEAD_INIT(name) { &(name), &(name) } 27 | 28 | #define LIST_HEAD(name) \ 29 | struct list_head name = LIST_HEAD_INIT(name) 30 | 31 | #define INIT_LIST_HEAD(ptr) do { \ 32 | (ptr)->next = (ptr); (ptr)->prev = (ptr); \ 33 | } while (0) 34 | 35 | /* 36 | * Insert a new entry between two known consecutive entries. 37 | * 38 | * This is only for internal list manipulation where we know 39 | * the prev/next entries already! 40 | */ 41 | static inline void 42 | __list_add(struct list_head *n, 43 | struct list_head *prev, 44 | struct list_head *next) 45 | { 46 | next->prev = n; 47 | n->next = next; 48 | n->prev = prev; 49 | prev->next = n; 50 | } 51 | 52 | /* 53 | * Delete a list entry by making the prev/next entries 54 | * point to each other. 55 | * 56 | * This is only for internal list manipulation where we know 57 | * the prev/next entries already! 58 | */ 59 | static inline void 60 | __list_del(struct list_head *prev, struct list_head *next) 61 | { 62 | next->prev = prev; 63 | prev->next = next; 64 | } 65 | 66 | static inline void 67 | __list_splice(struct list_head *list, struct list_head *head) 68 | { 69 | struct list_head *first = list->next; 70 | struct list_head *last = list->prev; 71 | struct list_head *at = head->next; 72 | 73 | first->prev = head; 74 | head->next = first; 75 | 76 | last->next = at; 77 | at->prev = last; 78 | } 79 | 80 | /** 81 | * list_add - add a new entry 82 | * @new: new entry to be added 83 | * @head: list head to add it after 84 | * 85 | * Insert a new entry after the specified head. 86 | * This is good for implementing stacks. 87 | */ 88 | static inline void 89 | list_add(struct list_head *n, struct list_head *head) 90 | { 91 | __list_add(n, head, head->next); 92 | } 93 | 94 | /** 95 | * list_add_tail - add a new entry 96 | * @new: new entry to be added 97 | * @head: list head to add it before 98 | * 99 | * Insert a new entry before the specified head. 100 | * This is useful for implementing queues. 101 | */ 102 | static inline void 103 | list_add_tail(struct list_head *n, struct list_head *head) 104 | { 105 | __list_add(n, head->prev, head); 106 | } 107 | 108 | /** 109 | * list_del - deletes entry from list. 110 | * @entry: the element to delete from the list. 111 | * Note: list_empty on entry does not return true after this, the entry is in an undefined state. 112 | */ 113 | static inline void 114 | list_del(struct list_head *entry) 115 | { 116 | __list_del(entry->prev, entry->next); 117 | entry->next = NULL; 118 | entry->prev = NULL; 119 | } 120 | 121 | /** 122 | * list_del_init - deletes entry from list and reinitialize it. 123 | * @entry: the element to delete from the list. 124 | */ 125 | static inline void 126 | list_del_init(struct list_head *entry) 127 | { 128 | __list_del(entry->prev, entry->next); 129 | INIT_LIST_HEAD(entry); 130 | } 131 | 132 | /** 133 | * list_move - delete from one list and add as another's head 134 | * @list: the entry to move 135 | * @head: the head that will precede our entry 136 | */ 137 | static inline void 138 | list_move(struct list_head *list, struct list_head *head) 139 | { 140 | __list_del(list->prev, list->next); 141 | list_add(list, head); 142 | } 143 | 144 | /** 145 | * list_move_tail - delete from one list and add as another's tail 146 | * @list: the entry to move 147 | * @head: the head that will follow our entry 148 | */ 149 | static inline void 150 | list_move_tail(struct list_head *list, struct list_head *head) 151 | { 152 | __list_del(list->prev, list->next); 153 | list_add_tail(list, head); 154 | } 155 | 156 | /** 157 | * list_empty - tests whether a list is empty 158 | * @head: the list to test. 159 | */ 160 | static inline int 161 | list_empty(const struct list_head *head) 162 | { 163 | return head->next == head; 164 | } 165 | 166 | /** 167 | * list_splice - join two lists 168 | * @list: the new list to add. 169 | * @head: the place to add it in the first list. 170 | */ 171 | static inline void 172 | list_splice(struct list_head *list, struct list_head *head) 173 | { 174 | if (!list_empty(list)) 175 | __list_splice(list, head); 176 | } 177 | 178 | /** 179 | * list_splice_init - join two lists and reinitialise the emptied list. 180 | * @list: the new list to add. 181 | * @head: the place to add it in the first list. 182 | * 183 | * The list at @list is reinitialised 184 | */ 185 | static inline void list_splice_init(struct list_head *list, 186 | struct list_head *head) 187 | { 188 | if (!list_empty(list)) { 189 | __list_splice(list, head); 190 | INIT_LIST_HEAD(list); 191 | } 192 | } 193 | 194 | /** 195 | * list_entry - get the struct for this entry 196 | * @ptr: the &struct list_head pointer. 197 | * @type: the type of the struct this is embedded in. 198 | * @member: the name of the list_struct within the struct. 199 | */ 200 | #define list_entry(ptr, type, member) \ 201 | (reinterpret_cast((char *)(ptr)-(char *)(&(reinterpret_cast(1)->member))+1)) 202 | 203 | /** 204 | * list_for_each - iterate over a list 205 | * @pos: the &struct list_head to use as a loop counter. 206 | * @head: the head for your list. 207 | */ 208 | #define list_for_each(pos, head) \ 209 | for (pos = (head)->next; pos != (head); \ 210 | pos = pos->next) 211 | /** 212 | * list_for_each_prev - iterate over a list backwards 213 | * @pos: the &struct list_head to use as a loop counter. 214 | * @head: the head for your list. 215 | */ 216 | #define list_for_each_prev(pos, head) \ 217 | for (pos = (head)->prev; pos != (head); \ 218 | pos = pos->prev) 219 | 220 | /** 221 | * list_for_each_safe - iterate over a list safe against removal of list entry 222 | * @pos: the &struct list_head to use as a loop counter. 223 | * @n: another &struct list_head to use as temporary storage 224 | * @head: the head for your list. 225 | */ 226 | #define list_for_each_safe(pos, n, head) \ 227 | for (pos = (head)->next, n = pos->next; pos != (head); \ 228 | pos = n, n = pos->next) 229 | 230 | /** 231 | * list_for_each_entry - iterate over list of given type 232 | * @pos: the type * to use as a loop counter. 233 | * @head: the head for your list. 234 | * @member: the name of the list_struct within the struct. 235 | */ 236 | #define list_for_each_entry(pos, head, member) \ 237 | for (pos = list_entry((head)->next, typeof(*pos), member); \ 238 | &pos->member != (head); \ 239 | pos = list_entry(pos->member.next, typeof(*pos), member)) 240 | 241 | /** 242 | * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry 243 | * @pos: the type * to use as a loop counter. 244 | * @n: another type * to use as temporary storage 245 | * @head: the head for your list. 246 | * @member: the name of the list_struct within the struct. 247 | */ 248 | #define list_for_each_entry_safe(pos, n, head, member) \ 249 | for (pos = list_entry((head)->next, typeof(*pos), member), \ 250 | n = list_entry(pos->member.next, typeof(*pos), member); \ 251 | &pos->member != (head); \ 252 | pos = n, n = list_entry(n->member.next, typeof(*n), member)) 253 | 254 | 255 | #endif 256 | -------------------------------------------------------------------------------- /include/lib/edmonds_karp.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * EDMONS-KARP ALGORITM 9 | * 10 | * Features: 11 | * In computer science and graph theory, the Edmonds–Karp algorithm is an 12 | * implementation of the Ford–Fulkerson method for computing the maximum flow in 13 | * a flow network in O(V E2) time. It is asymptotically slower than the 14 | * relabel-to-front algorithm, which runs in O(V3) time, but it is often faster 15 | * in practice for sparse graphs. The algorithm was first published by Yefim 16 | * (Chaim) Dinic in 1970[1] and independently published by Jack Edmonds and 17 | * Richard Karp in 1972.[2] Dinic's algorithm includes additional techniques 18 | * that reduce the running time to O(V2E). 19 | * 20 | * http://en.wikipedia.org/wiki/Edmonds–Karp_algorithm 21 | * 22 | ******************************************************************************/ 23 | 24 | #ifndef __EDMONDS_KARP_H__ 25 | #define __EDMONDS_KARP_H__ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "directed_graph.h" 32 | #include "hash_table.h" 33 | #include "queue.h" 34 | #include "2darray.h" 35 | 36 | namespace alg 37 | { 38 | /** 39 | * Edmonds Karp maximal flow class 40 | */ 41 | class EdmondsKarp 42 | { 43 | private: 44 | const Graph & g; 45 | Array2D m_residual; // residual network , 2d array 46 | HashTable m_pre; // pre node of current node 47 | bool * m_visits; // mark whether current node is visited 48 | 49 | HashTable m_map; // vertex id to ordinary row/col number mapping 50 | HashTable m_rmap; // reverse mapping of map. 51 | 52 | public: 53 | EdmondsKarp(const Graph & graph): 54 | g(graph), 55 | m_residual(g.vertex_count(), g.vertex_count()), 56 | m_pre(g.vertex_count()), 57 | m_map(g.vertex_count()), m_rmap(g.vertex_count()) 58 | { 59 | m_visits = new bool[g.vertex_count()]; 60 | // map vertex ids to ordinal row/col number, and reverse mapping. 61 | // for residual network, using sequential order 62 | Graph::Adjacent * a; 63 | int id=0; 64 | list_for_each_entry(a, &g.list(), a_node){ 65 | m_map[a->v.id] = id; 66 | m_rmap[id] = a->v.id; 67 | id++; 68 | } 69 | 70 | // init residual network 71 | m_residual.clear(0); 72 | 73 | list_for_each_entry(a, &g.list(), a_node){ 74 | Graph::Vertex * v; 75 | list_for_each_entry(v, &a->v_head, v_node){ 76 | int from = m_map[a->v.id]; 77 | int to = m_map[v->id]; 78 | m_residual(from, to) = v->weight; 79 | } 80 | } 81 | } 82 | 83 | ~EdmondsKarp() 84 | { 85 | delete [] m_visits; 86 | } 87 | 88 | /** 89 | * edmonds karp algorithm for maximal flow 90 | * returns the maxflow from src to sink 91 | */ 92 | uint32_t run(uint32_t src, uint32_t sink) 93 | { 94 | // find augument path repeatedly. 95 | int _src = m_map[src]; 96 | int _sink = m_map[sink]; 97 | 98 | uint32_t maxflow = 0; 99 | 100 | while(find_path(_src, _sink)) { 101 | int delta = INT_MAX; 102 | 103 | // find minimal delta 104 | int i; 105 | for (i=_sink;i!=_src;i= m_pre[i]) { 106 | delta = Min(delta, m_residual(m_pre[i],i)); 107 | } 108 | 109 | // for each edge, change residual network 110 | for (i=_sink; i!=_src;i= m_pre[i]) { 111 | m_residual(m_pre[i],i) -= delta; 112 | m_residual(i,m_pre[i]) += delta; 113 | } 114 | 115 | maxflow += delta; 116 | } 117 | 118 | return maxflow; 119 | } 120 | 121 | inline const Array2D & residual() const { return m_residual;} 122 | inline const HashTable & map() const { return m_map;} 123 | inline const HashTable & rmap() const { return m_rmap;} 124 | 125 | private: 126 | /** 127 | * find a augument path. using breadth first search 128 | */ 129 | bool find_path(uint32_t _src, uint32_t _sink) 130 | { 131 | Queue Q(g.vertex_count()); 132 | 133 | // clear visit flag & path 134 | memset(m_visits, false, sizeof(bool) * g.vertex_count()); 135 | 136 | // src setting 137 | m_pre[_src] = _src; 138 | m_visits[_src] = true; 139 | Q.enqueue(_src); 140 | 141 | while(!Q.is_empty()) { 142 | int p = Q.front(); 143 | Q.dequeue(); 144 | 145 | for (uint32_t i=0;i< g.vertex_count();i++) { 146 | if (m_residual(p,i) >0 && !m_visits[i]) { 147 | m_pre[i] = p; 148 | m_visits[i] = true; 149 | 150 | if (i==_sink) { // nice, we've got to sink point. 151 | return true; 152 | } 153 | Q.enqueue(i); 154 | } 155 | } 156 | } 157 | 158 | return false; 159 | } 160 | }; 161 | } 162 | 163 | #endif // 164 | -------------------------------------------------------------------------------- /include/lib/generic.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * GENERIC METHODS FOR ALGORITHMS 9 | * 10 | ******************************************************************************/ 11 | 12 | #ifndef __ALG_INC_H__ 13 | #define __ALG_INC_H__ 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "utils/gb18030.h" 20 | #include "utils/byteorder.h" 21 | 22 | 23 | #define Max(a, b) ( (a > b) ? a : b ) 24 | #define Min(a, b) ( (a < b) ? a : b ) 25 | 26 | namespace alg 27 | { 28 | /** 29 | * swap 2-element, orignal value 30 | */ 31 | template 32 | static inline void swap(T &x, T &y) 33 | { 34 | T _t(x); 35 | x = y; 36 | y = _t; 37 | } 38 | 39 | /** 40 | * print all of the elements in `list` with size `n` 41 | */ 42 | template 43 | static void printlist(T & list,int count) 44 | { 45 | int i; 46 | for(i=0;i=i); 57 | typeof(i) length = j - i; 58 | return i+(rand()%length); 59 | } 60 | 61 | /** 62 | * pass in array with *len 63 | * return new length 64 | */ 65 | template 66 | static uint32_t remove_dup(T a[], uint32_t len) 67 | { 68 | uint32_t i; 69 | uint32_t newlen = len; 70 | for (i=0; iv_node); 48 | delete v; 49 | } 50 | } 51 | 52 | const Vertex & vertex() const { return v;} 53 | 54 | void delete_vertex(uint32_t id) 55 | { 56 | Vertex * v, *vn; 57 | list_for_each_entry_safe(v, vn, &v_head, v_node){ 58 | if (v->id == id ) { 59 | list_del(&v->v_node); 60 | num_neigh--; 61 | delete v; 62 | break; 63 | } 64 | } 65 | } 66 | 67 | /** 68 | * get the Vertex from an adjacent list, according to vertex id 69 | */ 70 | Vertex * operator[] (uint32_t id) const 71 | { 72 | Vertex * v; 73 | list_for_each_entry(v, &v_head, v_node){ 74 | if (v->id == id) { 75 | return v; 76 | } 77 | } 78 | return NULL; 79 | } 80 | }; 81 | 82 | protected: 83 | uint32_t num_vertex; 84 | uint32_t num_edges; 85 | struct list_head a_head; // list header 86 | public: 87 | Graph() 88 | { 89 | num_vertex = 0; 90 | num_edges = 0; 91 | INIT_LIST_HEAD(&a_head); 92 | } 93 | 94 | virtual ~Graph() 95 | { 96 | Adjacent * a, *an; 97 | list_for_each_entry_safe(a, an, &a_head, a_node){ 98 | list_del(&a->a_node); 99 | delete a; 100 | } 101 | } 102 | private: 103 | Graph(const Graph &); 104 | Graph& operator=(const Graph &); 105 | public: 106 | uint32_t vertex_count() const { return num_vertex; } 107 | uint32_t edge_count() const { return num_edges; } 108 | /** 109 | * find an adjacent list with vertex id == id 110 | */ 111 | Adjacent * operator[] (uint32_t id) const 112 | { 113 | Adjacent * a; 114 | list_for_each_entry(a, &a_head, a_node){ 115 | if (a->v.id == id) { return a;} 116 | } 117 | 118 | return NULL; 119 | } 120 | 121 | /** 122 | * print a graph 123 | */ 124 | void print() const 125 | { 126 | Adjacent * a; 127 | printf("Graph : %d vertex, %d edges\n", num_vertex,num_edges); 128 | list_for_each_entry(a, &a_head, a_node){ 129 | printf("%d(neigh:%d)->{", a->v.id, a->num_neigh); 130 | Vertex * v; 131 | list_for_each_entry(v, &a->v_head, v_node){ 132 | printf("%d(w:%d)\t", v->id, v->weight); 133 | } 134 | printf("}\n"); 135 | } 136 | } 137 | 138 | const list_head & list() const {return a_head; } 139 | 140 | // Interface 141 | virtual bool add_vertex(uint32_t id) = 0; 142 | virtual void delete_vertex(uint32_t id) = 0; 143 | virtual bool add_edge(uint32_t x, uint32_t y, int32_t weight) = 0; 144 | virtual void delete_edge(uint32_t x, uint32_t y) = 0; 145 | 146 | protected: 147 | /** 148 | * test if an edge exists 149 | */ 150 | bool is_adjacent(const struct Adjacent * from, const struct Adjacent * to) 151 | { 152 | struct Vertex * v; 153 | list_for_each_entry(v, &from->v_head, v_node){ 154 | if (v->id == to->v.id ) { return true; } 155 | } 156 | return false; 157 | } 158 | }; 159 | } 160 | 161 | #endif // 162 | -------------------------------------------------------------------------------- /include/lib/graph_search.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * BREADTH FIRST SEARCH 9 | * 10 | * Features: 11 | * In graph theory, breadth-first search (BFS) is a strategy for searching in 12 | * a graph when search is limited to essentially two operations: 13 | * (a) visit and inspect a node of a graph; 14 | * (b) gain access to visit the nodes that neighbor the currently visited node. 15 | * The BFS begins at a root node and inspects all the neighboring nodes. Then 16 | * for each of those neighbor nodes in turn, it inspects their neighbor nodes 17 | * which were unvisited, and so on. Compare it with the depth-first search. 18 | * 19 | * http://en.wikipedia.org/wiki/Breadth-first_search 20 | * 21 | ******************************************************************************/ 22 | 23 | #ifndef __BREADTH_FIRST_SEARCH_H__ 24 | #define __BREADTH_FIRST_SEARCH_H__ 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include "queue.h" 31 | #include "stack.h" 32 | #include "directed_graph.h" 33 | #include "hash_table.h" 34 | 35 | namespace alg 36 | { 37 | static void breadth_first_search(const Graph & g, uint32_t source) 38 | { 39 | static const uint32_t MARK = 0xDEAD; 40 | 41 | Graph::Adjacent * root = g[source]; 42 | HashTable ht(g.vertex_count()); 43 | 44 | if (root==NULL) return; 45 | 46 | // init 47 | Queue Q(g.vertex_count()); 48 | Q.enqueue(root->v.id); 49 | ht[root->v.id] = MARK; 50 | 51 | while(!Q.is_empty()) { 52 | uint32_t t = Q.front(); 53 | printf("%d->", t); 54 | Q.dequeue(); 55 | Graph::Vertex * v; 56 | Graph::Adjacent * a = g[t]; 57 | list_for_each_entry(v, &a->v_head, v_node) { 58 | if (!ht.contains(v->id) || ht[v->id]!=MARK) { 59 | ht[v->id] = MARK; 60 | Q.enqueue(v->id); 61 | } 62 | } 63 | } 64 | 65 | printf("\n"); 66 | } 67 | 68 | static void depth_first_search(const Graph & g, uint32_t source) 69 | { 70 | static const uint32_t MARK = 0xDEAD; 71 | 72 | Graph::Adjacent * root = g[source]; 73 | HashTable ht(g.vertex_count()); 74 | 75 | if (root==NULL) return; 76 | 77 | // init 78 | Stack S(g.vertex_count()); 79 | S.push(root->v.id); 80 | ht[root->v.id] = MARK; 81 | 82 | while(!S.is_empty()) { 83 | uint32_t t = S.top(); 84 | printf("%d->", t); 85 | S.pop(); 86 | Graph::Vertex * v; 87 | Graph::Adjacent * a = g[t]; 88 | list_for_each_entry(v, &a->v_head, v_node) { 89 | if (!ht.contains(v->id) || ht[v->id] !=MARK) { 90 | ht[v->id] = MARK; 91 | S.push(v->id); 92 | } 93 | } 94 | } 95 | 96 | printf("\n"); 97 | } 98 | } 99 | 100 | #endif // 101 | -------------------------------------------------------------------------------- /include/lib/hash_multi.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * HASH BY MULTIPLICATION 9 | * 10 | * Features: 11 | * 1. h(k) = (A*k mod 2^w) >> (w-r) 12 | * 2. bucket size(m): 2^r, eg, m = 8 = 2^3 13 | * 3. w: word size (usually 32-bit) 14 | * 4. the value of A is chosen between 2^(w-r) and 2^w odd number. 15 | * 16 | ******************************************************************************/ 17 | 18 | #ifndef __HASH_MULTIPLICATION_H__ 19 | #define __HASH_MULTIPLICATION_H__ 20 | 21 | #include 22 | #include 23 | #include "generic.h" 24 | #include "prime.h" 25 | 26 | namespace alg 27 | { 28 | struct MultiHash { 29 | uint64_t A; 30 | uint32_t r; // prime, init your hash table with size -> r 31 | }; 32 | 33 | static const short BITWIDTH=32; 34 | static inline uint32_t multi_hash_table_size(const struct MultiHash * ht) { return 1<<(ht->r); } 35 | 36 | /** 37 | * multi_hash. 38 | */ 39 | static inline uint32_t multi_hash(const struct MultiHash * ht, uint32_t key) 40 | { 41 | uint32_t hash; 42 | hash = ((ht->A * key)&0xFFFFFFFF)>>(BITWIDTH-ht->r); //mod 2^w equals logic bitmask ops 43 | return hash; 44 | } 45 | 46 | /** 47 | * init a hash table with size specified. 48 | */ 49 | static MultiHash * multi_hash_init(uint32_t size) 50 | { 51 | // find prime larger than log2(size) 52 | uint32_t r = ceil(log2(size)); 53 | int i; 54 | for (i = r; ;i++) { 55 | if (is_prime(i)) { 56 | r = i; 57 | break; 58 | } 59 | } 60 | 61 | MultiHash * ht = new MultiHash; 62 | uint32_t a = 1 << (BITWIDTH-r); 63 | ht->A = a+1; 64 | ht->r = r; 65 | 66 | return ht; 67 | } 68 | } 69 | #endif // 70 | -------------------------------------------------------------------------------- /include/lib/hash_string.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * STRING HASH FUNCTION 9 | * 10 | * code taken from: 11 | * http://en.wikipedia.org/wiki/Java_hashCode() 12 | * 13 | ******************************************************************************/ 14 | 15 | #ifndef __STRING_HASH_H__ 16 | #define __STRING_HASH_H__ 17 | 18 | #include 19 | 20 | namespace alg 21 | { 22 | /** 23 | * hash a string into integer 24 | * using java's hashCode() implementation 25 | */ 26 | static uint32_t hash_string(const char * str, uint32_t len) 27 | { 28 | uint32_t hash=0; 29 | uint32_t i; 30 | for (i=0;i 6 | * _| 7 | * 8 | * GENERIC HASH TABLE 9 | * 10 | * Features: 11 | * 1. separate chaining for resolving collisions 12 | * 13 | * http://en.wikipedia.org/wiki/Hash_table 14 | * 15 | ******************************************************************************/ 16 | 17 | #ifndef __HASH_TABLE_H__ 18 | #define __HASH_TABLE_H__ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "double_linked_list.h" 24 | #include "hash_multi.h" 25 | 26 | namespace alg 27 | { 28 | /** 29 | * definition of a hash table. 30 | */ 31 | template 32 | class HashTable { 33 | private: 34 | /** 35 | * definiton of Key-Value pair. 36 | */ 37 | struct HashKV { 38 | uint32_t key; // 32-bit key 39 | T value; // value 40 | struct list_head node; // KV is a list element. 41 | }; 42 | 43 | private: 44 | uint32_t m_size; // the size of the hash table. 45 | struct list_head * m_slots; // all of the slots, each slot is an linked-list 46 | struct MultiHash * m_multi; // the hash function parameter. 47 | 48 | public: 49 | /** 50 | * create a hash table with max size . 51 | */ 52 | HashTable(uint32_t max) { 53 | // init multiplication hash function 54 | m_multi = multi_hash_init(max); 55 | m_size = multi_hash_table_size(m_multi); 56 | m_slots = new list_head[m_size]; 57 | 58 | for (uint32_t i=0; inode); 69 | delete kv; 70 | } 71 | } 72 | 73 | delete m_multi; 74 | delete [] m_slots; 75 | } 76 | private: 77 | HashTable(const HashTable &); 78 | HashTable& operator=(const HashTable &); 79 | public: 80 | 81 | /** 82 | * test if the hash table has the key 83 | */ 84 | bool contains(uint32_t key) const 85 | { 86 | // hash the key using a hash function. 87 | uint32_t hash = multi_hash(m_multi, key); 88 | 89 | // we iterate through the list. 90 | HashKV * kv; 91 | list_for_each_entry(kv, &m_slots[hash], node){ 92 | if (kv->key == key) { // ok, found in the list. 93 | return true; 94 | } 95 | } 96 | return false; 97 | } 98 | 99 | /** 100 | * delete by key 101 | */ 102 | bool delete_key(uint32_t key) 103 | { 104 | // hash the key using a hash function. 105 | uint32_t hash = multi_hash(m_multi, key); 106 | 107 | HashKV * kv, *nkv; 108 | list_for_each_entry_safe(kv,nkv,&m_slots[hash], node) { 109 | if (kv->key == key) { 110 | list_del(&kv->node); 111 | delete kv; 112 | return true; 113 | } 114 | } 115 | 116 | return false; 117 | } 118 | 119 | // const version of operator [] 120 | const T& operator[] (uint32_t key) const 121 | { 122 | // hash the key using a hash function. 123 | uint32_t hash = multi_hash(m_multi, key); 124 | 125 | // we iterate through the list. 126 | HashKV * kv; 127 | list_for_each_entry(kv, &m_slots[hash], node){ 128 | if (kv->key == key) { // ok, found in the list. 129 | return kv->value; 130 | } 131 | } 132 | 133 | // reaching here means a new key is given, 134 | // create a new HashKV struct for it. 135 | kv = new HashKV; 136 | kv->key = key; 137 | list_add(&kv->node, &m_slots[hash]); 138 | return kv->value; 139 | } 140 | 141 | /** 142 | * operator [] 143 | */ 144 | T& operator[] (uint32_t key) 145 | { 146 | return const_cast(static_cast(*this)[key]); 147 | } 148 | 149 | void clear() 150 | { 151 | HashKV * kv, *nkv; 152 | for (uint32_t i=0;inode); 155 | delete kv; 156 | } 157 | } 158 | } 159 | }; 160 | } 161 | 162 | #endif // 163 | -------------------------------------------------------------------------------- /include/lib/heap.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * Heap Data structure 9 | * 10 | * Heaps can be used as an array. For any key at array position I, 11 | I left child is at ( 2i ), right child is at ( 2i+1 ) and parent is 12 | I at (int) (i / 2). Heap size is stored at index 0. 13 | * 14 | * Basic operations of a heap are: 15 | * 16 | * 1. Insert – Insert an key. 17 | * 2. Delete minimum – Delete and return the smallest item in the heap. 18 | * 19 | * http://en.wikipedia.org/wiki/Binary_heap 20 | ******************************************************************************/ 21 | 22 | #ifndef __HEAP_H__ 23 | #define __HEAP_H__ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace alg 32 | { 33 | /** 34 | * define binary heap structure. 35 | */ 36 | template 37 | class Heap { 38 | private: 39 | /** 40 | * define key-value pair of heap struct. 41 | */ 42 | struct KV { 43 | public: 44 | int key; 45 | T value; 46 | }; 47 | uint32_t m_size; // current heap size. 48 | uint32_t m_max; // max heap size. 49 | KV * m_kvs; // key value pairs. 50 | 51 | public: 52 | Heap(int max) 53 | { 54 | m_size = 0; 55 | m_max = max+1; 56 | m_kvs = new KV[m_max]; 57 | m_kvs[0].key = INT_MIN; 58 | }; 59 | 60 | ~Heap() 61 | { 62 | delete [] m_kvs; 63 | }; 64 | 65 | private: 66 | Heap(const Heap &); 67 | Heap& operator=(const Heap&); 68 | 69 | public: 70 | 71 | inline int min_key() const { return m_kvs[1].key; }; 72 | inline const T & min_value() const { return m_kvs[1].value; }; 73 | 74 | // for loop through the kvs 75 | inline uint32_t count() const { return m_size; }; 76 | inline const T & operator[] (uint32_t idx) const { return m_kvs[idx+1].value; }; 77 | 78 | /** 79 | * insert a 'key'->'value' pair into the heap. 80 | */ 81 | void insert(int key, const T & value) 82 | { 83 | // heap full, just return; 84 | if(m_size == m_max) return; 85 | 86 | m_size++; 87 | m_kvs[m_size].key = key; 88 | m_kvs[m_size].value = value; 89 | 90 | /*Adjust its position*/ 91 | int now = m_size; 92 | while(m_kvs[now/2].key > key) 93 | { 94 | m_kvs[now] = m_kvs[now/2]; 95 | now /= 2; 96 | } 97 | 98 | m_kvs[now].key = key; 99 | m_kvs[now].value = value; 100 | } 101 | 102 | /** 103 | * emptiness test 104 | */ 105 | inline bool is_empty() const { return (m_size==0)?true:false; } 106 | 107 | /** 108 | * clear the heap 109 | */ 110 | inline void clear() { m_size = 0; } 111 | 112 | /** 113 | * contains test 114 | */ 115 | bool contains(const T & value) 116 | { 117 | for(uint32_t i=1;i<=m_size;i++) { 118 | if(m_kvs[i].value == value) return true; 119 | } 120 | 121 | return false; 122 | } 123 | 124 | /** 125 | * delete the min element --> heap top. 126 | */ 127 | void delete_min() 128 | { 129 | // heap[1] is the minimum key. So we remove heap[1]. 130 | // Size of the heap is decreased. Now heap[1] has to be filled. 131 | // We put the last key in its place and see if it fits. If it 132 | // does not fit, take minimum key among both its children and 133 | // replaces parent with it. Again See if the last key fits 134 | //in that place. 135 | int lastKey; 136 | T lastValue; 137 | uint32_t child,now; 138 | 139 | // empty heap, just return 140 | if (m_size == 0) return; 141 | 142 | lastKey = m_kvs[m_size].key; 143 | lastValue = m_kvs[m_size].value; 144 | m_size--; 145 | 146 | // now refers to the index at which we are now 147 | for(now = 1; now*2 <= m_size ;now = child) 148 | { 149 | // child is the index of the key which is minimum among 150 | // both the children, Indexes of children are i*2 and i*2 + 1 151 | child = now*2; 152 | // child!=heapSize beacuse heap[heapSize+1] does not exist, 153 | // which means it has only one child 154 | if(child != m_size && 155 | m_kvs[child+1].key < m_kvs[child].key) { 156 | child++; // choose the minium one. 157 | } 158 | // To check if the last key fits or not it suffices to check 159 | // if the last key is less than the minimum key among both the children 160 | if(lastKey > m_kvs[child].key) { 161 | m_kvs[now] = m_kvs[child]; 162 | } 163 | else { // It fits there 164 | break; 165 | } 166 | } 167 | 168 | m_kvs[now].key = lastKey; 169 | m_kvs[now].value= lastValue; 170 | } 171 | 172 | /** 173 | * so called DECREASE KEY operation. 174 | * step 1. find the value 175 | * step 2. decrease the key to the newkey 176 | */ 177 | void decrease_key(const T & value, int newkey) 178 | { 179 | uint32_t index = m_size+1; 180 | for (uint32_t i=1;i<=m_size;i++) { 181 | if (m_kvs[i].value == value) { 182 | index = i; 183 | break; 184 | } 185 | } 186 | 187 | if (index > m_size) return; // value not found 188 | 189 | if (newkey >= m_kvs[index].key) return; // violate DECREASE meanning. 190 | 191 | int now = index; 192 | while(m_kvs[now/2].key > newkey) 193 | { 194 | m_kvs[now] = m_kvs[now/2]; 195 | now /= 2; 196 | } 197 | 198 | m_kvs[now].key = newkey; 199 | m_kvs[now].value= value; 200 | } 201 | }; 202 | } 203 | 204 | #endif // 205 | -------------------------------------------------------------------------------- /include/lib/huffman.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * HUFFMAN CODING 9 | * 10 | * Features: 11 | * In computer science and information theory, Huffman coding is an entropy 12 | * encoding algorithm used for lossless data compression. The term refers to the 13 | * use of a variable-length code table for encoding a source symbol (such as a 14 | * character in a file) where the variable-length code table has been derived in 15 | * a particular way based on the estimated probability of occurrence for each 16 | * possible value of the source symbol. It was developed by David A. Huffman 17 | * while he was a Ph.D. student at MIT, and published in the 1952 paper 18 | * "A Method for the Construction of Minimum-Redundancy Codes" 19 | * 20 | * http://en.wikipedia.org/wiki/Huffman_coding 21 | * 22 | ******************************************************************************/ 23 | 24 | #ifndef __HUFFMAN_CODING_H__ 25 | #define __HUFFMAN_CODING_H__ 26 | 27 | #include 28 | #include 29 | 30 | #include "priority_queue.h" 31 | #include "hash_table.h" 32 | #include "stack.h" 33 | 34 | namespace alg 35 | { 36 | 37 | /** 38 | * The Huffman tree definition 39 | */ 40 | class HuffTree { 41 | private: 42 | /** 43 | * The Huffman tree node definition 44 | */ 45 | struct HuffNode{ 46 | unsigned char symbol; 47 | struct HuffNode *left, *right; 48 | }; 49 | 50 | /** 51 | * The code for a symbol of huffman 52 | */ 53 | struct HuffCode { 54 | char code[256]; // max length is 256 55 | uint32_t length; // the length of the code; 56 | }; 57 | 58 | private: 59 | HashTable m_symbol; // hash table for encoding 60 | HuffNode * m_root; // the root node for decoding 61 | uint32_t m_freqs[256]; // frequency array, you can pass this array 62 | // to the peer for constructing huffman 63 | // tree. 64 | public: 65 | /** 66 | * Construct a Huffman Tree with a sample string. 67 | * the string is either the characteristic of the text 68 | * or simply the original text to compress. 69 | */ 70 | HuffTree(const char * sample) : m_symbol(256) { 71 | // count frequency for each char(8-bit). 72 | memset(m_freqs, 0, sizeof(m_freqs)); 73 | 74 | int i; 75 | for(i=0; sample[i]!='\0'; i++) 76 | m_freqs[(unsigned char) sample[i]]++; 77 | 78 | recreate_from_freqs(); 79 | }; 80 | 81 | ~HuffTree() { 82 | // TODO: free HuffNodes 83 | }; 84 | 85 | private: 86 | HuffTree(const HuffTree&); 87 | HuffTree& operator=(const HuffTree&); 88 | public: 89 | 90 | /** 91 | * Encoding 92 | * encode a message into codes, codes should be large enough to hold the output 93 | * eg:. the length of string 94 | * the length in BITS will be returned. 95 | */ 96 | uint32_t encode(const char * msg, char * codes) 97 | { 98 | uint32_t cursor = 0; 99 | for(uint32_t i=0; msg[i]!='\0'; i++) 100 | { 101 | HuffCode & hcode = m_symbol[(uint32_t)msg[i]]; 102 | 103 | for (uint32_t j=0;jleft == NULL && node->right == NULL) { 135 | printf("%c",node->symbol); 136 | node = m_root; //reset tree 137 | } 138 | 139 | uint32_t off = cursor%8; 140 | uint32_t base= cursor/8; 141 | 142 | char bit = codes[base] & (1<<(7-off)); 143 | 144 | if (bit == 0) { 145 | node = node->left; 146 | } else { 147 | node = node->right; 148 | } 149 | } 150 | 151 | if(node->left == NULL && node->right == NULL) { 152 | printf("%c",node->symbol); 153 | } 154 | 155 | printf("\n"); 156 | }; 157 | 158 | private: 159 | /** 160 | * recreate the huff tree from an array[256] i.e. 8bit 161 | * useful for peer reconstructing decoding tree. 162 | */ 163 | void recreate_from_freqs() { 164 | // construct a priority queue for huffman tree building 165 | PQ pq; 166 | 167 | int i; 168 | for(i=0; i<256; i++) 169 | if(m_freqs[i] !=0) 170 | { 171 | HuffNode * n = new HuffNode(); 172 | n->left = NULL; 173 | n->right = NULL; 174 | n->symbol = (unsigned char) i; 175 | 176 | pq.queue(n, m_freqs[i]); // freq. as priority 177 | } 178 | 179 | // tree building subroutine 180 | while(pq.count()>1) 181 | { 182 | int prio1, prio2, newprio; 183 | HuffNode * node1, *node2, *new_node; 184 | 185 | node1 = pq.top(&prio1); pq.dequeue(); 186 | node2 = pq.top(&prio2); pq.dequeue(); 187 | 188 | newprio = prio1+prio2; 189 | 190 | new_node = new HuffNode; 191 | new_node->left = node1; 192 | new_node->right = node2; 193 | 194 | pq.queue(new_node, newprio); 195 | } 196 | 197 | // set root 198 | int prio; 199 | m_root = pq.top(&prio); 200 | pq.dequeue(); 201 | 202 | // construct symbol lookup table 203 | char code[256]; 204 | build_symbol(m_root, 0, code); 205 | }; 206 | 207 | /** 208 | * building symbol lookup table 209 | */ 210 | void build_symbol(struct HuffNode * node, int k, char code[256]) { 211 | //If we reach the leaf node we introduce the code in the table 212 | if(node->left == NULL && node->right == NULL) 213 | { 214 | code[k] = '\0'; 215 | HuffCode hcode; 216 | strncpy(hcode.code, code, k); 217 | hcode.length = k; 218 | m_symbol[(uint32_t)node->symbol] = hcode; 219 | // printf("k %d, code :%s symbol %d-> %c\n",k, hcode->code, node->symbol, node->symbol); 220 | } 221 | 222 | //We concatenate a 0 for each step to the left 223 | if(node->left!=NULL) 224 | { 225 | code[k] = '0'; 226 | build_symbol(node->left, k+1,code); 227 | } 228 | 229 | //We concatenate a 1 for each step to the right 230 | if(node->right!=NULL) 231 | { 232 | code[k] = '1'; 233 | build_symbol(node->right, k+1,code); 234 | } 235 | }; 236 | }; 237 | } 238 | 239 | #endif // 240 | -------------------------------------------------------------------------------- /include/lib/imath.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * COMMON MATH OPS 9 | * 10 | ******************************************************************************/ 11 | 12 | #ifndef __IMATH_H__ 13 | #define __IMATH_H__ 14 | 15 | #include 16 | #include 17 | 18 | namespace alg 19 | { 20 | /** 21 | * dot product of given arrays K and A of len, saved in SUM 22 | */ 23 | static uint32_t dot_product(const uint32_t * K, const uint32_t * A, uint32_t len) 24 | { 25 | uint32_t i; 26 | uint32_t sum = 0; 27 | for (i=0; i 6 | * _| 7 | * 8 | * INSERTION SORT 9 | * 10 | * 1. sort array in O(n^2) time. 11 | * 12 | * http://en.wikipedia.org/wiki/Insertion_sort 13 | * 14 | ******************************************************************************/ 15 | 16 | #ifndef __INSERTION_SORT_H__ 17 | #define __INSERTION_SORT_H__ 18 | 19 | namespace alg 20 | { 21 | /** 22 | * insertion sort an array 23 | */ 24 | template 25 | static void insertion_sort(T *array , int number_of_elements) 26 | { 27 | int iter,jter; 28 | for(iter=1;iter=0 && array[jter] > current_element) 33 | { 34 | array[jter+1] = array[jter]; 35 | jter--; 36 | } 37 | array[jter+1] = current_element; 38 | } 39 | } 40 | } 41 | 42 | #endif // 43 | -------------------------------------------------------------------------------- /include/lib/integer.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * INTEGER -- OF ARBITARY LENGTH 9 | * 10 | * Retrieved from: 11 | * http://en.literateprograms.org/Arbitrary-precision_integer_arithmetic_(C)?oldid=16902 12 | * 13 | ******************************************************************************/ 14 | 15 | #ifndef __INTEGER_H__ 16 | #define __INTEGER_H__ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "generic.h" 25 | 26 | namespace alg 27 | { 28 | class Integer 29 | { 30 | private: 31 | typedef unsigned short component_t; 32 | typedef unsigned long double_component_t; 33 | 34 | #define Max_COMPONENT ((component_t)(-1)) 35 | #define COMPONENT_BITS (sizeof(component_t)*CHAR_BIT) 36 | 37 | #define LOG_2_10 3.3219280948873623478703194294894 38 | 39 | component_t* c; /* least-significant word first */ 40 | int num_components; 41 | 42 | public: 43 | Integer(int components) 44 | { 45 | num_components = components; 46 | c = new component_t[components]; 47 | memset(c, 0, sizeof(component_t)*num_components); 48 | } 49 | 50 | Integer(const Integer & rhs) 51 | { 52 | num_components = rhs.size(); 53 | c = new component_t[num_components]; 54 | memcpy(c, rhs.components(), num_components*sizeof(component_t)); 55 | } 56 | 57 | ~Integer() 58 | { 59 | delete [] c; 60 | } 61 | 62 | inline const component_t & operator[] (int i) const { return c[i]; } 63 | inline component_t & operator[] (int i) { return c[i]; } 64 | 65 | inline const component_t * components() const { return c; } 66 | inline uint32_t size() const { return num_components; } 67 | 68 | static const Integer from_string(const char* s) 69 | { 70 | Integer result((int)ceil(LOG_2_10*strlen(s)/COMPONENT_BITS)); 71 | Integer digit(1); 72 | 73 | int i; 74 | for (i = 0; s[i] != '\0'; i++) { 75 | result = result*10; 76 | digit[0] = s[i] - '0'; 77 | result = result + digit; 78 | } 79 | 80 | return result; 81 | } 82 | 83 | char * to_string() const 84 | { 85 | Integer x = (*this); 86 | int i, result_len; 87 | char* result = new char[(int)ceil(COMPONENT_BITS*size()/LOG_2_10) + 2]; 88 | 89 | Integer ten(1); 90 | ten[0] = 10; 91 | 92 | if (x.is_zero()) { 93 | strcpy(result, "0"); 94 | } else { 95 | for (i = 0; !x.is_zero(); i++) { 96 | result[i] = (char)(x%10) + '0'; 97 | x=x/10; 98 | } 99 | result[i] = '\0'; 100 | } 101 | 102 | result_len = strlen(result); 103 | for(i=0; i < result_len/2; i++) { 104 | char temp = result[i]; 105 | result[i] = result[result_len - i - 1]; 106 | result[result_len - i - 1] = temp; 107 | } 108 | 109 | return result; 110 | } 111 | 112 | bool is_zero() 113 | { 114 | uint32_t i; 115 | for(i=0; i < size(); i++) { 116 | if ((*this)[i] != 0) return false; 117 | } 118 | return true; 119 | } 120 | 121 | // Integer Assignment 122 | Integer & operator= (const Integer & source) 123 | { 124 | memmove(c, source.components(), sizeof(component_t)*Min(source.size(), size())); 125 | 126 | if (size() > source.size()) { 127 | memset(c + source.size(), 0, sizeof(component_t)*(size() - source.size())); 128 | } 129 | 130 | return (*this); 131 | } 132 | 133 | const Integer operator+ (const Integer & rhs) 134 | { 135 | Integer result(Max(size(), rhs.size())+1); 136 | 137 | double_component_t carry = 0; 138 | uint32_t i; 139 | for(i=0; i Max_COMPONENT) { 145 | partial_sum &= Max_COMPONENT; 146 | carry = 1; 147 | } 148 | result[i] = (component_t)partial_sum; 149 | } 150 | for ( ; i < result.size(); i++) { result[i] = 0; } 151 | 152 | return result; 153 | } 154 | 155 | const Integer operator- (const Integer & right) 156 | { 157 | Integer result(Max(size(), right.size())); 158 | 159 | int borrow = 0; 160 | uint32_t i; 161 | for(i=0; i> COMPONENT_BITS; 195 | result[i] = (component_t)(partial_sum & Max_COMPONENT); 196 | } 197 | return result; 198 | } 199 | 200 | const Integer operator* (const Integer & rhs) 201 | { 202 | Integer result(Max(size(), rhs.size())*2); 203 | 204 | uint32_t i, lidx, ridx; 205 | double_component_t carry = 0; 206 | uint32_t max_size_no_carry; 207 | uint32_t left_max_component = size() - 1; 208 | uint32_t right_max_component = rhs.size() - 1; 209 | while((*this)[left_max_component] == 0) left_max_component--; 210 | while(rhs[right_max_component] == 0) right_max_component--; 211 | max_size_no_carry = left_max_component + right_max_component; 212 | for(i=0; i <= max_size_no_carry || carry != 0; i++) { 213 | double_component_t partial_sum = carry; 214 | carry = 0; 215 | lidx = Min(i, left_max_component); 216 | ridx = i - lidx; 217 | while(lidx >= 0 && ridx <= right_max_component) { 218 | partial_sum += ((double_component_t)(*this)[lidx])*rhs[ridx]; 219 | carry += partial_sum >> COMPONENT_BITS; 220 | partial_sum &= Max_COMPONENT; 221 | lidx--; ridx++; 222 | } 223 | result[i] = partial_sum; 224 | } 225 | for ( ; i < result.size(); i++) { result[i] = 0; } 226 | return result; 227 | } 228 | 229 | const Integer operator/ (component_t rhs) 230 | { 231 | Integer result(size()); 232 | double_component_t dividend = 0; 233 | int i; 234 | for (i = size() - 1; i >= 0; i--) { 235 | dividend |= (*this)[i]; 236 | result[i] = dividend/rhs; 237 | dividend = (dividend % rhs) << COMPONENT_BITS; 238 | } 239 | 240 | return result; 241 | } 242 | 243 | component_t operator% (component_t right) 244 | { 245 | double_component_t mod_two_power = 1; 246 | double_component_t result = 0; 247 | uint32_t i, bit; 248 | for(i=0; i= right) { 253 | result -= right; 254 | } 255 | } 256 | mod_two_power <<= 1; 257 | if (mod_two_power >= right) { 258 | mod_two_power -= right; 259 | } 260 | } 261 | } 262 | return (component_t)result; 263 | } 264 | 265 | const Integer operator% (const Integer & rhs) 266 | { 267 | Integer result = rhs; 268 | Integer mod_two_power(rhs.size() + 1); 269 | 270 | uint32_t i, bit; 271 | mod_two_power[0] = 1; 272 | for(i=0; i= 0) { 277 | result = result - rhs; 278 | } 279 | } 280 | mod_two_power.shift_left_one_integer(); 281 | if (mod_two_power.compare(rhs) >= 0) { 282 | mod_two_power = mod_two_power - rhs; 283 | } 284 | } 285 | } 286 | 287 | return result; 288 | } 289 | 290 | int compare(const Integer & rhs) 291 | { 292 | uint32_t i = Max(size() - 1, rhs.size() - 1); 293 | for ( ; i >= 0; i--) { 294 | component_t left_comp = 295 | (i < size()) ? (*this)[i] : 0; 296 | component_t right_comp = 297 | (i < rhs.size()) ? rhs[i] : 0; 298 | if (left_comp < right_comp) 299 | return -1; 300 | else if (left_comp > right_comp) 301 | return 1; 302 | } 303 | return 0; 304 | } 305 | 306 | private: 307 | void shift_left_one_integer() 308 | { 309 | uint32_t i; 310 | (*this)[size() - 1] <<= 1; 311 | for (i = size() - 2; i >= 0; i--) { 312 | (*this)[i + 1] |= (*this)[i] >> (COMPONENT_BITS - 1); 313 | (*this)[i] <<= 1; 314 | } 315 | } 316 | 317 | void shift_right_one_integer() 318 | { 319 | uint32_t i; 320 | (*this)[0] >>= 1; 321 | for (i = 1; i < size(); i++) { 322 | (*this)[i - 1] |= ((*this)[i] & 1) << (COMPONENT_BITS - 1); 323 | (*this)[i] >>= 1; 324 | } 325 | } 326 | }; 327 | } 328 | 329 | #endif // 330 | -------------------------------------------------------------------------------- /include/lib/interval_tree.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * INTERVAL-TREE 9 | * 10 | * Features: 11 | * 1. red-black tree based 12 | * 2. O(logn) lookup performance 13 | * 3. range search [low, high] 14 | * 15 | * http://en.wikipedia.org/wiki/Interval_tree 16 | * 17 | ******************************************************************************/ 18 | 19 | #ifndef __INTERVAL_TREE_H__ 20 | #define __INTERVAL_TREE_H__ 21 | 22 | #include 23 | #include 24 | #include 25 | #include "generic.h" 26 | #include "stack.h" 27 | #include "double_linked_list.h" 28 | #include "rbtree.h" 29 | 30 | namespace alg 31 | { 32 | class IntervalTree:public RBTreeAbstract 33 | { 34 | public: 35 | /** 36 | * Interval-Tree node definition 37 | */ 38 | typedef struct ivltree_node_t : public rbtree_node_t { 39 | int low; // lower-bound 40 | int high; // higher-bound 41 | int m; // max subtree upper bound value 42 | } * ivltree_node; 43 | 44 | #define IVLNODE(rbnode) static_cast(rbnode) 45 | #define IVLNODE_M(rbnode) (rbnode?IVLNODE(rbnode)->m:INT_MIN) 46 | 47 | public: 48 | /** 49 | * ivltree_create 50 | * initialized an interval tree 51 | * same as init an red-black tree 52 | */ 53 | IntervalTree() { } 54 | 55 | /** 56 | * ivltree_lookup 57 | * 58 | * search range [low, high] for overlap, return only one element 59 | * use lookup & delete & insert schema to get multiple elements 60 | * 61 | * NULL is returned if not found. 62 | */ 63 | ivltree_node lookup(int low, int high) 64 | { 65 | ivltree_node n = IVLNODE(get_root()); 66 | while (n != NULL && (low > n->high || n->low > high)) { // should search in childs 67 | if (n->left !=NULL && low <=IVLNODE(n->left)->m) n = IVLNODE(n->left); // path choice on m. 68 | else n = IVLNODE(n->right); 69 | } 70 | 71 | return n; 72 | } 73 | 74 | /** 75 | * ivltree_insert 76 | * insert range [low, high] into red-black tree 77 | */ 78 | void insert(int low, int high) 79 | { 80 | ivltree_node inserted_node = new_node(low, high, RED, NULL, NULL); 81 | if (get_root() == NULL) { 82 | set_root(inserted_node); 83 | } else { 84 | ivltree_node n = IVLNODE(get_root()); 85 | while (1) { 86 | // update 'm' for each node traversed from root 87 | if (inserted_node->m > n->m) { 88 | n->m = inserted_node->m; 89 | } 90 | 91 | // find a proper position 92 | if (low < n->low) { 93 | if (n->left == NULL) { 94 | n->left = inserted_node; 95 | break; 96 | } else { 97 | n = IVLNODE(n->left); 98 | } 99 | } else { 100 | if (n->right == NULL) { 101 | n->right = inserted_node; 102 | break; 103 | } else { 104 | n = IVLNODE(n->right); 105 | } 106 | } 107 | } 108 | inserted_node->parent = n; 109 | } 110 | insert_case1(inserted_node); 111 | } 112 | 113 | /** 114 | * delete the key in the red-black tree 115 | */ 116 | void delete_key(ivltree_node n) 117 | { 118 | rbtree_node child; 119 | if (n == NULL) return; 120 | 121 | // phase 1. fixup the 'm' value until m is not the max value of the path. 122 | fixup_m(n); 123 | 124 | // phase 2. red black tree deletion 125 | if (n->left != NULL && n->right != NULL) { 126 | /* Copy key/value from predecessor and then delete it instead */ 127 | ivltree_node pred = IVLNODE(maximum_node(n->left)); 128 | n->low = pred->low; 129 | n->high= pred->high; 130 | n = pred; 131 | } 132 | 133 | assert(n->left == NULL || n->right == NULL); 134 | child = n->right == NULL ? n->left : n->right; 135 | if (node_color(n) == BLACK) { 136 | n->color = node_color(child); 137 | delete_case1(n); 138 | } 139 | replace_node(n, child); 140 | if (n->parent == NULL && child != NULL) 141 | child->color = BLACK; 142 | 143 | delete(n); 144 | } 145 | 146 | void print() { 147 | print_helper(IVLNODE(get_root()), 0); 148 | puts(""); 149 | } 150 | 151 | void print_helper(ivltree_node n, int indent) { 152 | int i; 153 | 154 | if (n == NULL) { 155 | fputs("", stdout); 156 | return; 157 | } 158 | 159 | if (n->right != NULL) { 160 | print_helper(IVLNODE(n->right), indent + INDENT_STEP); 161 | } 162 | for(i=0; icolor == BLACK) 165 | printf("[%d %d, m->%d]\n", n->low,n->high,n->m); 166 | else 167 | printf("*[%d %d, m->%d]\n", n->low, n->high,n->m); 168 | if (n->left != NULL) { 169 | print_helper(IVLNODE(n->left), indent + INDENT_STEP); 170 | } 171 | } 172 | 173 | 174 | private: 175 | /** 176 | * fix 'm' value caused by rotation 177 | */ 178 | void rotate_left_callback(rbtree_node n, rbtree_node parent) 179 | { 180 | // parent inherit max m value 181 | IVLNODE(parent)->m = IVLNODE(n)->m; 182 | // update node 'm' value by it's children. 183 | IVLNODE(n)->m = Max(IVLNODE(n)->high, Max(IVLNODE_M(n->left), IVLNODE_M(n->right))); 184 | } 185 | 186 | void rotate_right_callback(rbtree_node n, rbtree_node parent) 187 | { 188 | rotate_left_callback(n, parent); 189 | } 190 | 191 | /** 192 | * fix up 'm' value caued by deletion 193 | */ 194 | void fixup_m(rbtree_node n) 195 | { 196 | int m = IVLNODE(n)->m; 197 | int m_new = Max(IVLNODE_M(n->left), IVLNODE_M(n->right)); 198 | 199 | // if current 'm' is not decided by n->high, just return. 200 | if (m==m_new) return; 201 | 202 | while(n->parent !=NULL) { 203 | /* 204 | parent(high) 205 | / \ 206 | n(m_new) sibling(m) 207 | 208 | */ 209 | IVLNODE(n->parent)->m = 210 | Max(IVLNODE(n->parent)->high, Max(m_new, IVLNODE_M(sibling(n)))); 211 | 212 | if(IVLNODE_M(n->parent) > m) break; // since node n does not affect 213 | // the result anymore, we break. 214 | n = n->parent; 215 | } 216 | } 217 | 218 | /** 219 | * create a new node, and set default vales. 220 | */ 221 | ivltree_node new_node(int low, int high, color rbtree_node_color, rbtree_node left, rbtree_node right) 222 | { 223 | ivltree_node result = new ivltree_node_t; 224 | result->low = low; 225 | result->high = high; 226 | result->m = high; 227 | result->color = rbtree_node_color; 228 | result->left = left; 229 | result->right = right; 230 | if(left !=NULL) left->parent = result; 231 | if(right!=NULL) right->parent = result; 232 | result->parent = NULL; 233 | return result; 234 | } 235 | }; 236 | } 237 | 238 | #endif // 239 | -------------------------------------------------------------------------------- /include/lib/lcs.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * LARGEST COMMON SEQUENCE 9 | * 10 | * http://en.wikipedia.org/wiki/Longest_common_subsequence_problem 11 | * 12 | ******************************************************************************/ 13 | 14 | #ifndef __LCS_H__ 15 | #define __LCS_H__ 16 | 17 | #include "generic.h" 18 | #include "2darray.h" 19 | #include "stack.h" 20 | 21 | namespace alg 22 | { 23 | /** 24 | * calculate Length matrix 25 | * X -- array of size m 26 | * Y -- array of size n 27 | * eg: 28 | 0 1 2 3 4 5 6 7 29 | Ø M Z J A W X U 30 | 0 Ø 0 0 0 0 0 0 0 0 31 | 1 X 0 0 0 0 0 0 1 1 32 | 2 M 0 1 1 1 1 1 1 1 33 | 3 J 0 1 1 2 2 2 2 2 34 | 4 Y 0 1 1 2 2 2 2 2 35 | 5 A 0 1 1 2 3 3 3 3 36 | 6 U 0 1 1 2 3 3 3 4 37 | 7 Z 0 1 2 2 3 3 3 4 38 | */ 39 | template 40 | static Array2D * lcs_length(const T X[], uint32_t m, const T Y[], uint32_t n) 41 | { 42 | Array2D & A = *new Array2D(m+1,n+1); 43 | 44 | uint32_t i,j; 45 | 46 | // set initial state 47 | for(i=0; i<=m; i++) { 48 | A(i,0) = 0; 49 | } 50 | 51 | for(j=0; j<=n; j++) { 52 | A(0,j) = 0; 53 | } 54 | 55 | for(i=1;i<=m;i++) { 56 | for(j=1;j<=n;j++) { 57 | if(X[i-1]==Y[j-1]) A(i,j) = A(i-1,j-1) + 1; 58 | else A(i,j) = Max(A(i,j-1), A(i-1,j)); 59 | } 60 | } 61 | 62 | return &A; 63 | }; 64 | 65 | /** 66 | * pass an empty stack, pop out the result in sequential order. 67 | */ 68 | template 69 | static void lcs_backtrack(Stack & S, struct Array2D & A, 70 | const T X[], const T Y[], 71 | const uint32_t i, uint32_t j) 72 | { 73 | if (i==0 || j==0) return; 74 | else if (X[i-1] == Y[j-1]) { 75 | S.push(X[i-1]); 76 | lcs_backtrack(S, A, X, Y, i-1, j-1); 77 | } 78 | else { 79 | if (A(i, j-1) > A(i-1, j)) 80 | lcs_backtrack(S, A, X, Y, i, j-1); 81 | else 82 | lcs_backtrack(S, A, X, Y, i-1, j); 83 | } 84 | } 85 | } 86 | 87 | #endif // 88 | -------------------------------------------------------------------------------- /include/lib/merge_sort.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * MERGE SORT 9 | * 10 | * Features: 11 | * This is divide and conquer algorithm. This works as follows. 12 | * (1) Divide the input which we have to sort into two parts in the middle. Call it the left part 13 | * and right part. 14 | * Example: Say the input is -10 32 45 -78 91 1 0 -16 then the left part will be 15 | * -10 32 45 -78 and the right part will be 91 1 0 6. 16 | * (2) Sort Each of them seperately. Note that here sort does not mean to sort it using some other 17 | * method. We already wrote fucntion to sort it. Use the same. 18 | * (3) Then merge the two sorted parts. 19 | * 20 | * ------------ 21 | * Worst case performance O(n log n) 22 | * Best case performance 23 | * O(n log n) typical, 24 | * O(n) natural variant 25 | * Average case performance O(n log n) 26 | * Worst case space complexity O(n) auxiliary 27 | * ------------ 28 | * 29 | * Merge sort can easily be optmized for parallized computing. 30 | * 31 | * http://en.wikipedia.org/wiki/Merge_sort 32 | * 33 | ******************************************************************************/ 34 | 35 | #ifndef __MERGE_SORT_H__ 36 | #define __MERGE_SORT_H__ 37 | 38 | namespace alg 39 | { 40 | /** 41 | * Merge functions merges the two sorted parts. Sorted parts will be from [left, mid] and [mid+1, right]. 42 | */ 43 | template 44 | static void __merge(T *array, int left, int mid, int right) 45 | { 46 | /*We need a Temporary array to store the new sorted part*/ 47 | T tempArray[right-left+1]; 48 | int pos=0,lpos = left,rpos = mid + 1; 49 | while(lpos <= mid && rpos <= right) 50 | { 51 | if(array[lpos] < array[rpos]) 52 | { 53 | tempArray[pos++] = array[lpos++]; 54 | } 55 | else 56 | { 57 | tempArray[pos++] = array[rpos++]; 58 | } 59 | } 60 | while(lpos <= mid) tempArray[pos++] = array[lpos++]; 61 | while(rpos <= right)tempArray[pos++] = array[rpos++]; 62 | int iter; 63 | /* Copy back the sorted array to the original array */ 64 | for(iter = 0;iter < pos; iter++) 65 | { 66 | array[iter+left] = tempArray[iter]; 67 | } 68 | return; 69 | } 70 | 71 | /** 72 | * sort an array from left->right 73 | */ 74 | template 75 | static void merge_sort(T *array, int left, int right) 76 | { 77 | int mid = (left+right)/2; 78 | /* We have to sort only when left 6 | * _| 7 | * 8 | * PERFECT HASH 9 | * 10 | * http://en.wikipedia.org/wiki/Perfect_hash 11 | * 12 | ******************************************************************************/ 13 | #ifndef __PERFECT_HASH_H__ 14 | #define __PERFECT_HASH_H__ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "generic.h" 20 | #include "universal_hash.h" 21 | #include "stack.h" 22 | 23 | namespace alg 24 | { 25 | template 26 | class PerfHT 27 | { 28 | private: 29 | class PerfHTException: public std::exception 30 | { 31 | public: 32 | virtual const char * what() const throw() 33 | { 34 | return "key does not exist"; 35 | } 36 | }; 37 | 38 | // Level-2 Slot definition 39 | class SlotL2 { 40 | public: 41 | uint32_t cnt; // collison count 42 | uint32_t key; //key 43 | T value; // value 44 | }; 45 | 46 | // Level-1 Slot definition 47 | struct SlotL1 { 48 | public: 49 | uint32_t cnt; // collison count 50 | struct UHash params; // 2nd level 51 | struct SlotL2 * lv2_slots; // level 2 slots 52 | 53 | uint32_t key; // key 54 | T value; // value 55 | 56 | ~SlotL1() { 57 | if (cnt>1) delete [] lv2_slots; 58 | } 59 | }; 60 | 61 | struct SlotL1 * slots; // level 1 slots 62 | struct UHash params; // 1st level 63 | uint32_t num_slots; 64 | const PerfHTException error; 65 | 66 | public: 67 | PerfHT(uint32_t keys[], uint32_t len) 68 | { 69 | // remove duplicate keys 70 | uint32_t newlen = remove_dup(keys, len); 71 | 72 | // 1-level hashing 73 | uhash_init(&this->params, newlen); 74 | 75 | this->slots = new SlotL1[this->params.prime]; 76 | for(uint32_t i=0;iparams.prime;i++) { 77 | this->slots[i].cnt = 0; 78 | } 79 | 80 | for (uint32_t i = 0; i < newlen; i++) { 81 | uint32_t hash = uhash_integer(&this->params, keys[i]); 82 | slots[hash].cnt++; 83 | slots[hash].key = keys[i]; 84 | } 85 | 86 | // 2-level processing 87 | lv2_init(keys, newlen); 88 | }; 89 | 90 | ~PerfHT() { 91 | delete [] slots; 92 | } 93 | private: 94 | PerfHT(const PerfHT&); 95 | PerfHT& operator=(const PerfHT&); 96 | 97 | public: 98 | const T& operator[] (uint32_t key) const throw (PerfHTException) 99 | { 100 | uint32_t hash; 101 | hash = uhash_integer(¶ms, key); 102 | if (slots[hash].key == key) { 103 | return slots[hash].value; 104 | } else if (slots[hash].cnt > 1) { // maybe in the 2nd level slot 105 | SlotL1 & slot = slots[hash]; 106 | uint32_t hash2 = uhash_integer(&slot.params, key); 107 | 108 | // 2nd-level available 109 | if (slot.lv2_slots[hash2].key == key) { 110 | return slot.lv2_slots[hash2].value; 111 | } 112 | } 113 | 114 | throw error; 115 | } 116 | 117 | /** 118 | * operator [] 119 | */ 120 | T& operator[] (uint32_t key) throw (PerfHTException) 121 | { 122 | return const_cast(static_cast(*this)[key]); 123 | } 124 | 125 | private: 126 | /** 127 | * level-2 hash pre-work 128 | * collect collides for each level-1 slots 129 | */ 130 | void lv2_init(uint32_t keys[], uint32_t len) 131 | { 132 | for (uint32_t i = 0; i < params.prime; i++) { 133 | if (slots[i].cnt > 1) { 134 | // stacks for temporary storing keys 135 | Stack collides(len); 136 | 137 | // find collide keys 138 | for(uint32_t j=0;j & collides) 154 | { 155 | // init another hash function & 2nd level 156 | uhash_init(&lv1_slot->params, lv1_slot->cnt * lv1_slot->cnt); 157 | SlotL2 * lv2_slots = new SlotL2[lv1_slot->params.prime]; 158 | lv1_slot->lv2_slots = lv2_slots; 159 | 160 | retry: 161 | for(uint32_t i=0;iparams.prime;i++) { 162 | lv2_slots[i].cnt = 0; 163 | } 164 | 165 | // try another hash function 166 | uhash_init(&lv1_slot->params, lv1_slot->cnt * lv1_slot->cnt); 167 | 168 | // check collide 169 | for(uint32_t i=0; iparams, key); 172 | lv2_slots[hash].key = key; 173 | if (++lv2_slots[hash].cnt > 1) { goto retry; } 174 | } 175 | } 176 | }; 177 | } 178 | 179 | #endif // 180 | -------------------------------------------------------------------------------- /include/lib/prim_mst.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * PRIM'S ALGORITHM -- MINIMUM SPANNING TREE 9 | * 10 | * Features: 11 | * 12 | * Prim's algorithm is a greedy algorithm that finds a minimum spanning tree 13 | * for a connected weighted undirected graph. This means it finds a subset of 14 | * the edges that forms a tree that includes every vertex, where the total 15 | * weight of all the edges in the tree is minimized. The algorithm was 16 | * developed in 1930 by Czech mathematician Vojtěch Jarník and later 17 | * independently by computer scientist Robert C. Prim in 1957 and rediscovered 18 | * by Edsger Dijkstra in 1959. Therefore it is also sometimes called the DJP 19 | * algorithm, the Jarník algorithm, or the Prim–Jarník algorithm. 20 | * 21 | * http://en.wikipedia.org/wiki/Prim%27s_algorithm 22 | * 23 | ******************************************************************************/ 24 | 25 | #ifndef __PRIM_MST_H__ 26 | #define __PRIM_MST_H__ 27 | 28 | #include 29 | #include 30 | #include "undirected_graph.h" 31 | #include "double_linked_list.h" 32 | #include "heap.h" 33 | 34 | namespace alg 35 | { 36 | class Prim 37 | { 38 | private: 39 | /** 40 | * Prim's Adjacent Lists, for Prim's Algorithm caculation 41 | */ 42 | struct PrimAdjacent { 43 | Heap heap; // binary heap representation of weight->node 44 | // the top of the heap is always the minimal element 45 | const Graph::Vertex & v; 46 | 47 | PrimAdjacent(const Graph::Vertex & vertex, uint32_t num_neigh):heap(num_neigh),v(vertex) { } 48 | 49 | struct list_head pa_node; 50 | }; 51 | 52 | /** 53 | * Prim's Graph, simplified to list. 54 | */ 55 | typedef struct list_head PrimGraph; 56 | private: 57 | PrimGraph m_pg; 58 | public: 59 | /** 60 | * construct Prim's DataStrcuture by a given graph 61 | */ 62 | Prim(const Graph & g) 63 | { 64 | INIT_LIST_HEAD(&m_pg); 65 | 66 | Graph::Adjacent * a; 67 | list_for_each_entry(a, &g.list(), a_node){ 68 | add_adjacent(*a); 69 | } 70 | } 71 | 72 | ~Prim() 73 | { 74 | PrimAdjacent * pa, *pan; 75 | list_for_each_entry_safe(pa, pan, &m_pg, pa_node){ 76 | list_del(&pa->pa_node); 77 | delete pa; 78 | } 79 | } 80 | private: 81 | Prim(const Prim&); 82 | Prim& operator= (const Prim&); 83 | private: 84 | /** 85 | * add an adjacent list to prim's graph 86 | */ 87 | void add_adjacent(const Graph::Adjacent & a) 88 | { 89 | PrimAdjacent * pa = new PrimAdjacent(a.vertex(), a.num_neigh); 90 | list_add_tail(&pa->pa_node, &m_pg); 91 | 92 | Graph::Vertex * v; 93 | list_for_each_entry(v, &a.v_head, v_node){ 94 | pa->heap.insert(v->weight, v); // weight->vertex 95 | } 96 | } 97 | 98 | /** 99 | * lookup up a given id 100 | * the related adjacent list is returned. 101 | */ 102 | PrimAdjacent * lookup(uint32_t id) const 103 | { 104 | PrimAdjacent * pa; 105 | list_for_each_entry(pa, &m_pg, pa_node){ 106 | if (pa->v.id == id) { return pa;} 107 | } 108 | 109 | return NULL; 110 | } 111 | public: 112 | /** 113 | * Prim's Algorithm. 114 | * 115 | * Input: A non-empty connected weighted graph with vertices V and edges E 116 | * (the weights can be negative). 117 | * 118 | * Initialize: Vnew = {x}, where x is an arbitrary node (starting point) from V, Enew = {} 119 | * 120 | * Repeat until Vnew = V: 121 | * 1. Choose an edge {u, v} with minimal weight such that u is in Vnew and v 122 | * is not (if there are multiple edges with the same weight, any of them may be picked) 123 | * 2. Add v to Vnew, and {u, v} to Enew 124 | * 125 | * Output: Vnew and Enew describe a minimal spanning tree 126 | */ 127 | Graph * run() 128 | { 129 | UndirectedGraph * mst = new UndirectedGraph(); // empty set == Vnew 130 | 131 | // choose the first vertex as the starting point 132 | PrimAdjacent * pa; 133 | list_for_each_entry(pa, &m_pg, pa_node){ break; } 134 | const Graph::Vertex * v = &pa->v; 135 | mst->add_vertex(v->id); 136 | 137 | // Prim's Algorithm 138 | while(true) { 139 | int weight = INT_MAX; // loop tmp variables 140 | uint32_t best_to; 141 | struct PrimAdjacent * best_from; 142 | 143 | // for each Vnew, find a new vertex in V that has minimal weight. 144 | Graph::Adjacent * a; 145 | list_for_each_entry(a, &mst->list(), a_node){ 146 | pa = lookup(a->v.id); 147 | while (!pa->heap.is_empty()) { // find one neighbour 148 | v = pa->heap.min_value(); 149 | if ((*mst)[v->id]==NULL) { // if new V appears 150 | if (pa->heap.min_key() < weight) { 151 | weight = pa->heap.min_key(); 152 | best_to = v->id; 153 | best_from = pa; 154 | } 155 | break; 156 | } else { 157 | pa->heap.delete_min(); 158 | } 159 | } 160 | } 161 | 162 | if (weight != INT_MAX) { 163 | // congrats , new V & E 164 | mst->add_vertex(best_to); 165 | mst->add_edge(best_from->v.id, best_to, weight); 166 | best_from->heap.delete_min(); 167 | } else break; 168 | }; 169 | 170 | return mst; 171 | } 172 | 173 | /** 174 | * print the PrimGraph 175 | */ 176 | void print() 177 | { 178 | struct PrimAdjacent * pa; 179 | printf("Prim Graph: \n"); 180 | list_for_each_entry(pa, &m_pg, pa_node){ 181 | printf("%d->{", pa->v.id); 182 | for(uint32_t i=0;iheap.count();i++) { 183 | Graph::Vertex * v = pa->heap[i]; 184 | printf("id:%d->w:%d \t", v->id, v->weight); 185 | } 186 | printf("}\n"); 187 | } 188 | } 189 | }; 190 | } 191 | 192 | #endif // 193 | -------------------------------------------------------------------------------- /include/lib/prime.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * PRIME TEST FUNCTION 9 | * 10 | * http://en.wikipedia.org/wiki/Primality_test 11 | * 12 | ******************************************************************************/ 13 | #ifndef __PRIME_H__ 14 | #define __PRIME_H__ 15 | 16 | namespace alg 17 | { 18 | /** 19 | * check whether a given number is a prime number. 20 | */ 21 | static inline int is_prime(unsigned int n) 22 | { 23 | unsigned int p; 24 | if (!(n & 1) || n < 2 ) return n == 2; 25 | 26 | /* comparing p*p <= n can overflow */ 27 | for (p = 3; p <= n/p; p += 2) 28 | if (!(n % p)) return 0; 29 | return 1; 30 | } 31 | } 32 | 33 | #endif // 34 | -------------------------------------------------------------------------------- /include/lib/priority_queue.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * PRIORITY QUEUE 9 | * 10 | * Features: 11 | * 1. A queue with prioity implemented in double linked list. 12 | * 2. The queue is in ascending order of priority. 13 | * 14 | * http://en.wikipedia.org/wiki/Priority_queue 15 | * 16 | ******************************************************************************/ 17 | 18 | #ifndef __PRIORITY_QUEUE_H__ 19 | #define __PRIORITY_QUEUE_H__ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "double_linked_list.h" 26 | 27 | namespace alg 28 | { 29 | /** 30 | * definition of a Priority Queue. 31 | */ 32 | template 33 | class PQ { 34 | /** 35 | * definition of a node of priority queue. 36 | */ 37 | struct PQNode { 38 | int priority; 39 | T value; 40 | struct list_head node; 41 | }; 42 | 43 | private: 44 | uint32_t m_count; 45 | struct list_head m_head; 46 | public: 47 | /** 48 | * create an empty priority queue. 49 | */ 50 | PQ() 51 | { 52 | m_count = 0; 53 | INIT_LIST_HEAD(&m_head); 54 | } 55 | 56 | ~PQ() 57 | { 58 | PQNode * pos, * n; 59 | list_for_each_entry_safe(pos,n, &m_head, node) { 60 | list_del(&pos->node); 61 | delete pos; 62 | } 63 | } 64 | private: 65 | PQ(const PQ&); 66 | PQ& operator=(const PQ&); 67 | public: 68 | 69 | /** 70 | * queue a value with priority into the priority queue. 71 | */ 72 | void queue(const T &value, uint32_t priority) 73 | { 74 | PQNode * n = new PQNode; 75 | n->priority = priority; 76 | n->value = value; 77 | 78 | if (list_empty(&m_head)) // empty list, just add in. 79 | { 80 | list_add(&n->node, &m_head); 81 | m_count++; 82 | } 83 | else 84 | { 85 | // sequentially find the apropriate position 86 | PQNode * pos; 87 | bool found = false; 88 | list_for_each_entry(pos, &m_head, node) { 89 | if (n->priority <= pos->priority) { 90 | __list_add(&n->node, pos->node.prev, &pos->node); 91 | m_count++; 92 | found = true; 93 | break; 94 | } 95 | } 96 | 97 | if (!found) { // we reach the end of the list. 98 | list_add_tail(&n->node, &m_head); 99 | m_count++; 100 | } 101 | } 102 | } 103 | 104 | /** 105 | * return top element 106 | * check is_empty() before top(). 107 | */ 108 | inline const T & top(int * prio) const 109 | { 110 | PQNode * n; 111 | n = list_entry(m_head.next, PQNode, node); 112 | *prio = n->priority; 113 | return n->value; 114 | } 115 | 116 | /** 117 | * dequeue the most priority element, i.e. the first element. 118 | */ 119 | inline void dequeue() 120 | { 121 | if (list_empty(&m_head)) return; 122 | 123 | PQNode * n; 124 | n = list_entry(m_head.next, PQNode, node); 125 | list_del(&n->node); 126 | m_count--; 127 | delete n; 128 | } 129 | 130 | /** 131 | * test whether the priority queue is empty 132 | */ 133 | inline bool is_empty() const 134 | { 135 | if (list_empty(&m_head)) return true; 136 | return false; 137 | } 138 | 139 | /** 140 | * get the exact number of data 141 | */ 142 | inline uint32_t count() const { return m_count; } 143 | }; 144 | } 145 | 146 | #endif // 147 | -------------------------------------------------------------------------------- /include/lib/queue.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * QUEUE 8 | * 9 | * Features: 10 | * 1. Queue with capcity 11 | * 12 | * http://en.wikipedia.org/wiki/Queue_(data_structure) 13 | * 14 | ******************************************************************************/ 15 | 16 | #ifndef __QUEUE_H__ 17 | #define __QUEUE_H__ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | namespace alg 24 | { 25 | /** 26 | * Queue Definition 27 | */ 28 | template 29 | class Queue 30 | { 31 | private: 32 | class QueueEmptyException: public std::exception 33 | { 34 | public: 35 | virtual const char * what() const throw() 36 | { 37 | return "Queue is empty."; 38 | } 39 | }; 40 | 41 | private: 42 | uint32_t m_capacity; // queue capacity 43 | uint32_t m_size; // current queue size 44 | uint32_t m_front; // index of the first element 45 | uint32_t m_rear; // index of the last element 46 | T * m_elements; // the elements 47 | 48 | const QueueEmptyException exp_empty; 49 | 50 | public: 51 | /** 52 | * constructor takes argument the maximum number of elements the Queue 53 | * can hold, creates a Queue according to it and returns a pointer to the 54 | * Queue. 55 | */ 56 | Queue(uint32_t max) 57 | { 58 | this->m_elements = new T[max]; 59 | this->m_size = 0; 60 | this->m_capacity = max; 61 | this->m_front =0; 62 | this->m_rear = -1; 63 | }; 64 | 65 | ~Queue() 66 | { 67 | delete [] m_elements; 68 | }; 69 | private: 70 | Queue(const Queue &); 71 | Queue& operator=(const Queue &); 72 | public: 73 | /** 74 | * Dequeue 75 | */ 76 | inline void dequeue() 77 | { 78 | /* If Queue size is zero then it is empty. So we cannot pop */ 79 | if(m_size==0) { 80 | return; 81 | } 82 | /* Removing an element is equivalent to incrementing index of front by one */ 83 | else { 84 | m_size--; 85 | m_front++; 86 | /* As we fill elements in circular fashion */ 87 | if(m_front==m_capacity) { 88 | m_front=0; 89 | } 90 | } 91 | return; 92 | }; 93 | 94 | /** 95 | * return the front element. 96 | */ 97 | inline const T& front() const 98 | { 99 | if (m_size==0) throw exp_empty; 100 | return m_elements[m_front]; 101 | }; 102 | 103 | /** 104 | * test weather the queue is empty 105 | */ 106 | inline bool is_empty() const 107 | { 108 | if (m_size ==0) return true; 109 | return false; 110 | }; 111 | 112 | /** 113 | * enqueue an element 114 | * returns false when queue is full 115 | */ 116 | bool enqueue(const T & element) 117 | { 118 | // If the Queue is full, we cannot push an element into it 119 | // as there is no space for it.*/ 120 | if(m_size == m_capacity) { 121 | return false; 122 | } 123 | else { 124 | m_size++; 125 | m_rear++; 126 | /* As we fill the queue in circular fashion */ 127 | if(m_rear == m_capacity) { 128 | m_rear = 0; 129 | } 130 | /* Insert the element in its rear side */ 131 | m_elements[m_rear] = element; 132 | 133 | return true; 134 | } 135 | }; 136 | 137 | /** 138 | * return the queue count. 139 | */ 140 | inline int count() const { return m_size; }; 141 | }; 142 | } 143 | #endif // 144 | -------------------------------------------------------------------------------- /include/lib/quick_sort.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * QUICKSORT 9 | * 10 | * Features: 11 | * 1. sort array in O(nlogn) time. 12 | * 2. most generic fast sorting algorithm 13 | * 14 | * http://en.wikipedia.org/wiki/Quick_sort 15 | * 16 | ******************************************************************************/ 17 | 18 | #ifndef __QUICKSORT_H__ 19 | #define __QUICKSORT_H__ 20 | 21 | #include 22 | 23 | namespace alg 24 | { 25 | /** 26 | * the quick-sort partition routine 27 | */ 28 | template 29 | static int __partition(T list[],int begin, int end) 30 | { 31 | int pivot_idx = choose_pivot(begin,end); 32 | T pivot = list[pivot_idx]; 33 | swap(list[begin], list[pivot_idx]); 34 | 35 | int i = begin + 1; 36 | int j = end; 37 | 38 | while(i <= j) 39 | { 40 | while((i <= end) && (list[i] <= pivot)) 41 | i++; 42 | while((j >= begin) && (list[j] > pivot)) 43 | j--; 44 | if(i < j) 45 | swap(list[i],list[j]); 46 | } 47 | 48 | swap(list[begin],list[j]); 49 | return j; // final pivot position 50 | } 51 | 52 | /** 53 | * quick sort an array of range [begin, end] 54 | */ 55 | template 56 | static void quicksort(T list[],int begin,int end) 57 | { 58 | if( begin < end) 59 | { 60 | int pivot_idx = __partition(list, begin, end); 61 | quicksort(list, begin, pivot_idx-1); 62 | quicksort(list, pivot_idx+1, end); 63 | } 64 | } 65 | } 66 | 67 | #endif // 68 | -------------------------------------------------------------------------------- /include/lib/radix_sort.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * RADIX SORT 9 | * 10 | * Features: 11 | * 1. sort unsigned 32-bit array in O(n) time 12 | * 2. subset sorted with couting sort. 13 | * 14 | * http://en.wikipedia.org/wiki/Radix_sort 15 | * 16 | ******************************************************************************/ 17 | 18 | #ifndef __RADIX_SORT_H__ 19 | #define __RADIX_SORT_H__ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace alg 29 | { 30 | /** 31 | * couting sort 32 | */ 33 | static void __radix(int byte, const unsigned N, const uint32_t *source, uint32_t *dest) 34 | { 35 | unsigned count[256]; 36 | unsigned index[256]; 37 | memset(count, 0, sizeof (count)); 38 | 39 | unsigned i; 40 | for(i=0; i>(byte*8))&0xff]++; 42 | 43 | index[0]=0; 44 | for(i=1; i<256; ++i) 45 | index[i] = index[i-1] + count[i-1]; 46 | 47 | for(i=0; i>(byte*8))&0xff]++] = source[i]; 49 | } 50 | 51 | /** 52 | * radix sort a given unsigned 32-bit integer array of size N 53 | */ 54 | static void radix_sort(uint32_t *source, const unsigned N) 55 | { 56 | uint32_t * temp = new uint32_t[N]; 57 | __radix(0, N, source, temp); 58 | __radix(1, N, temp, source); 59 | __radix(2, N, source, temp); 60 | __radix(3, N, temp, source); 61 | 62 | delete [] temp; 63 | } 64 | 65 | /** 66 | * check whether the array is in order 67 | */ 68 | static void check_order(const uint32_t *data, unsigned N) 69 | { 70 | for(--N ; N > 0; --N, ++data) 71 | assert(data[0] <= data[1]); 72 | } 73 | } 74 | 75 | #endif // 76 | -------------------------------------------------------------------------------- /include/lib/random.h: -------------------------------------------------------------------------------- 1 | #ifndef __RANDOM_H__ 2 | #define __RANDOM_H__ 3 | 4 | #include 5 | #include 6 | 7 | #endif // 8 | -------------------------------------------------------------------------------- /include/lib/random_select.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * RANDOM-SELECT 9 | * 10 | * Features: 11 | * 1. select the smallest k-th element 12 | * 2. will modify orignal list 13 | * 14 | * http://en.wikipedia.org/wiki/Order_statistic 15 | * 16 | ******************************************************************************/ 17 | 18 | #ifndef __RANDOM_SELECT_H__ 19 | #define __RANDOM_SELECT_H__ 20 | 21 | namespace alg 22 | { 23 | /** 24 | * the random_select partition routine 25 | */ 26 | template 27 | static int __partition(T list[],int begin, int end) 28 | { 29 | int pivot_idx = choose_pivot(begin,end); 30 | T pivot = list[pivot_idx]; 31 | swap(list[begin],list[pivot_idx]); 32 | 33 | int i = begin + 1; 34 | int j = end; 35 | 36 | while(i <= j) 37 | { 38 | while((i <= end) && (list[i] <= pivot)) 39 | i++; 40 | while((j >= begin) && (list[j] > pivot)) 41 | j--; 42 | if(i < j) 43 | swap(list[i],list[j]); 44 | } 45 | 46 | swap(list[begin],list[j]); 47 | return j; // final pivot position 48 | } 49 | 50 | /** 51 | * select the k-th smallest number in 'list' of range [begin, end] 52 | */ 53 | template 54 | static int random_select(T list[], int begin, int end, int k) 55 | { 56 | if(begin == end) 57 | return begin; 58 | 59 | int pivot_idx = __partition(list, begin, end); 60 | int human_idx = pivot_idx - begin + 1; 61 | 62 | if(k == human_idx) 63 | return pivot_idx; 64 | if(k < human_idx) 65 | return random_select(list, begin, pivot_idx - 1, k); 66 | if(k > human_idx) 67 | return random_select(list, pivot_idx+1, end, k - human_idx); 68 | } 69 | } 70 | 71 | #endif // 72 | -------------------------------------------------------------------------------- /include/lib/rbtree.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * RED-BLACK TREE 9 | * 10 | * Features: 11 | * 1. balanced tree 12 | * 2. O(logn) lookup performance 13 | * 14 | * http://en.wikipedia.org/wiki/Red_black_tree 15 | * 16 | ******************************************************************************/ 17 | 18 | #ifndef __RBTREE_H__ 19 | #define __RBTREE_H__ 20 | #include 21 | #include 22 | #include 23 | #include "rbtree_defs.h" 24 | 25 | namespace alg 26 | { 27 | template 28 | class RBTree:public RBTreeAbstract 29 | { 30 | private: 31 | // a default Key-Value node. 32 | struct KVNode: public rbtree_node_t { 33 | KeyT key; 34 | ValueT value; 35 | }; 36 | 37 | #define KVNODE(node) static_cast(node) 38 | 39 | public: 40 | 41 | /** 42 | * rbtree_insert 43 | * insert a key-value pair into red-black tree 44 | */ 45 | void insert(const KeyT & key, const ValueT & value) 46 | { 47 | KVNode * inserted_node = new_node(key, value, RED, NULL, NULL); 48 | if (get_root() == NULL) { 49 | set_root(inserted_node); 50 | } else { 51 | KVNode * n = KVNODE(get_root()); 52 | while (1) { 53 | if (key == n->key) { 54 | n->value = value; 55 | /* inserted_node isn't going to be used, don't leak it */ 56 | delete (inserted_node); 57 | return; 58 | } else if (key < n->key) { 59 | if (n->left == NULL) { 60 | n->left = inserted_node; 61 | break; 62 | } else { 63 | n = static_cast(n->left); 64 | } 65 | } else { 66 | assert (key > n->key); 67 | if (n->right == NULL) { 68 | n->right = inserted_node; 69 | break; 70 | } else { 71 | n = static_cast(n->right); 72 | } 73 | } 74 | } 75 | inserted_node->parent = n; 76 | } 77 | insert_case1(inserted_node); 78 | } 79 | 80 | /** 81 | * contain test 82 | */ 83 | bool contains(KeyT key) 84 | { 85 | if (lookup_node(key)) 86 | return true; 87 | return false; 88 | } 89 | 90 | /** 91 | * rbtree_lookup 92 | * search in red-black tree 93 | */ 94 | ValueT operator [] (KeyT key) 95 | { 96 | KVNode * n = lookup_node(key); 97 | if (n==NULL) throw std::out_of_range ("no such key"); 98 | return n->value; 99 | } 100 | 101 | /** 102 | * delete the key in the red-black tree 103 | */ 104 | void delete_key(KeyT key) 105 | { 106 | rbtree_node child; 107 | KVNode * n = lookup_node(key); 108 | if (n == NULL) return; /* Key not found, do nothing */ 109 | if (n->left != NULL && n->right != NULL) { 110 | /* Copy key/value from predecessor and then delete it instead */ 111 | KVNode * pred = static_cast(maximum_node(n->left)); 112 | n->key = pred->key; 113 | n->value = pred->value; 114 | n = pred; 115 | } 116 | 117 | assert(n->left == NULL || n->right == NULL); 118 | child = n->right == NULL ? n->left : n->right; 119 | if (node_color(n) == BLACK) { 120 | n->color = node_color(child); 121 | delete_case1(n); 122 | } 123 | replace_node(n, child); 124 | if (n->parent == NULL && child != NULL) 125 | child->color = BLACK; 126 | delete(n); 127 | } 128 | 129 | void print() { 130 | print_helper(KVNODE(get_root()), 0); 131 | puts(""); 132 | } 133 | protected: 134 | void print_helper(KVNode * n, int indent) { 135 | int i; 136 | if (n == NULL) { 137 | fputs("", stdout); 138 | return; 139 | } 140 | if (n->right != NULL) { 141 | print_helper(KVNODE(n->right), indent + INDENT_STEP); 142 | } 143 | for(i=0; icolor == BLACK) 146 | printf("%d\n", (int)n->key); 147 | else 148 | printf("<%d>\n", (int)n->key); 149 | if (n->left != NULL) { 150 | print_helper(KVNODE(n->left), indent + INDENT_STEP); 151 | } 152 | } 153 | 154 | KVNode * new_node(KeyT key, ValueT value, color rbtree_node_color, rbtree_node left, rbtree_node right) { 155 | KVNode * result =new KVNode; 156 | result->key = key; 157 | result->value = value; 158 | result->color = rbtree_node_color; 159 | result->left = left; 160 | result->right = right; 161 | if (left != NULL) left->parent = result; 162 | if (right != NULL) right->parent = result; 163 | result->parent = NULL; 164 | return result; 165 | } 166 | 167 | KVNode * lookup_node(KeyT key) { 168 | KVNode * n = KVNODE(get_root()); 169 | while (n != NULL) { 170 | if (key == n->key) { 171 | return n; 172 | } else if (key < n->key) { 173 | n = KVNODE(n->left); 174 | } else { 175 | n = KVNODE(n->right); 176 | } 177 | } 178 | return n; 179 | } 180 | }; 181 | } 182 | 183 | #endif 184 | -------------------------------------------------------------------------------- /include/lib/rbtree_defs.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * RED-BLACK TREE DEFINITON 9 | * 10 | * Features: 11 | * 1. balanced tree 12 | * 2. O(logn) lookup performance 13 | * 14 | * http://en.wikipedia.org/wiki/Red_black_tree 15 | * 16 | ******************************************************************************/ 17 | 18 | #ifndef __RBTREE_DEFS_H__ 19 | #define __RBTREE_DEFS_H__ 20 | #include 21 | #include 22 | 23 | namespace alg 24 | { 25 | class RBTreeAbstract 26 | { 27 | protected: 28 | static const int INDENT_STEP=4; 29 | 30 | enum rbtree_node_color { RED, BLACK }; 31 | typedef enum rbtree_node_color color; 32 | 33 | typedef struct rbtree_node_t { 34 | rbtree_node_t* left; 35 | rbtree_node_t* right; 36 | rbtree_node_t* parent; 37 | enum rbtree_node_color color; 38 | } *rbtree_node; 39 | 40 | private: 41 | rbtree_node m_root; 42 | 43 | public: 44 | /** 45 | * init a red-black tree 46 | */ 47 | RBTreeAbstract() : m_root(NULL) {} 48 | 49 | virtual ~RBTreeAbstract() { destruct(m_root); } 50 | 51 | private: 52 | RBTreeAbstract(const RBTreeAbstract &); 53 | RBTreeAbstract& operator=(const RBTreeAbstract &); 54 | // 55 | void destruct(rbtree_node n) 56 | { 57 | if (n==NULL) return; 58 | destruct(n->left); 59 | destruct(n->right); 60 | delete n; 61 | } 62 | 63 | protected: 64 | // 65 | inline rbtree_node get_root( ) { return m_root; } 66 | inline void set_root(rbtree_node new_root) { m_root = new_root; } 67 | 68 | protected: 69 | /// 70 | /// THE RED-BLACK TREE CORE 71 | /// 72 | rbtree_node grandparent(rbtree_node n) 73 | { 74 | assert (n != NULL); 75 | assert (n->parent != NULL); /* Not the root rbtree_node */ 76 | assert (n->parent->parent != NULL); /* Not child of root */ 77 | return n->parent->parent; 78 | } 79 | 80 | rbtree_node sibling(rbtree_node n) 81 | { 82 | assert (n != NULL); 83 | assert (n->parent != NULL); /* Root rbtree_node has no sibling */ 84 | if (n == n->parent->left) 85 | return n->parent->right; 86 | else 87 | return n->parent->left; 88 | } 89 | 90 | rbtree_node uncle(rbtree_node n) 91 | { 92 | assert (n != NULL); 93 | assert (n->parent != NULL); /* Root rbtree_node has no uncle */ 94 | assert (n->parent->parent != NULL); /* Children of root have no uncle */ 95 | return sibling(n->parent); 96 | } 97 | 98 | color node_color(rbtree_node n) 99 | { 100 | return n == NULL ? BLACK : n->color; 101 | } 102 | 103 | /** 104 | * According to rotation operation, n1 is the node, n2 is parent node affected by rotation 105 | */ 106 | virtual void rotate_left_callback(rbtree_node n1, rbtree_node n2) { } 107 | 108 | virtual void rotate_right_callback(rbtree_node n1, rbtree_node n2) { } 109 | 110 | 111 | void rotate_left(rbtree_node n) 112 | { 113 | rbtree_node r = n->right; 114 | replace_node(n, r); 115 | n->right = r->left; 116 | if (r->left != NULL) { 117 | r->left->parent = n; 118 | } 119 | r->left = n; 120 | n->parent = r; 121 | 122 | rotate_left_callback(n, r); 123 | } 124 | 125 | void rotate_right(rbtree_node n) 126 | { 127 | rbtree_node L = n->left; 128 | replace_node(n, L); 129 | n->left = L->right; 130 | if (L->right != NULL) { 131 | L->right->parent = n; 132 | } 133 | L->right = n; 134 | n->parent = L; 135 | 136 | rotate_right_callback(n, L); 137 | } 138 | 139 | void replace_node(rbtree_node oldn, rbtree_node newn) 140 | { 141 | if (oldn->parent == NULL) { 142 | m_root = newn; 143 | } else { 144 | if (oldn == oldn->parent->left) 145 | oldn->parent->left = newn; 146 | else 147 | oldn->parent->right = newn; 148 | } 149 | if (newn != NULL) { 150 | newn->parent = oldn->parent; 151 | } 152 | } 153 | 154 | void insert_case1(rbtree_node n) 155 | { 156 | if (n->parent == NULL) 157 | n->color = BLACK; 158 | else 159 | insert_case2(n); 160 | } 161 | 162 | void insert_case2(rbtree_node n) 163 | { 164 | if (node_color(n->parent) == BLACK) 165 | return; /* Tree is still valid */ 166 | else 167 | insert_case3(n); 168 | } 169 | 170 | void insert_case3(rbtree_node n) 171 | { 172 | if (node_color(uncle(n)) == RED) { 173 | n->parent->color = BLACK; 174 | uncle(n)->color = BLACK; 175 | grandparent(n)->color = RED; 176 | insert_case1(grandparent(n)); 177 | } else { 178 | insert_case4(n); 179 | } 180 | } 181 | 182 | void insert_case4(rbtree_node n) 183 | { 184 | if (n == n->parent->right && n->parent == grandparent(n)->left) { 185 | rotate_left(n->parent); 186 | n = n->left; 187 | } else if (n == n->parent->left && n->parent == grandparent(n)->right) { 188 | rotate_right(n->parent); 189 | n = n->right; 190 | } 191 | insert_case5(n); 192 | } 193 | 194 | void insert_case5(rbtree_node n) 195 | { 196 | n->parent->color = BLACK; 197 | grandparent(n)->color = RED; 198 | if (n == n->parent->left && n->parent == grandparent(n)->left) { 199 | rotate_right(grandparent(n)); 200 | } else { 201 | assert (n == n->parent->right && n->parent == grandparent(n)->right); 202 | rotate_left(grandparent(n)); 203 | } 204 | } 205 | 206 | rbtree_node maximum_node(rbtree_node n) 207 | { 208 | assert (n != NULL); 209 | while (n->right != NULL) { 210 | n = n->right; 211 | } 212 | return n; 213 | } 214 | 215 | void delete_case1(rbtree_node n) 216 | { 217 | if (n->parent == NULL) 218 | return; 219 | else 220 | delete_case2(n); 221 | } 222 | 223 | void delete_case2(rbtree_node n) 224 | { 225 | if (node_color(sibling(n)) == RED) { 226 | n->parent->color = RED; 227 | sibling(n)->color = BLACK; 228 | if (n == n->parent->left) 229 | rotate_left(n->parent); 230 | else 231 | rotate_right(n->parent); 232 | } 233 | delete_case3(n); 234 | } 235 | 236 | void delete_case3(rbtree_node n) 237 | { 238 | if (node_color(n->parent) == BLACK && 239 | node_color(sibling(n)) == BLACK && 240 | node_color(sibling(n)->left) == BLACK && 241 | node_color(sibling(n)->right) == BLACK) 242 | { 243 | sibling(n)->color = RED; 244 | delete_case1(n->parent); 245 | } 246 | else 247 | delete_case4(n); 248 | } 249 | 250 | void delete_case4(rbtree_node n) 251 | { 252 | if (node_color(n->parent) == RED && 253 | node_color(sibling(n)) == BLACK && 254 | node_color(sibling(n)->left) == BLACK && 255 | node_color(sibling(n)->right) == BLACK) 256 | { 257 | sibling(n)->color = RED; 258 | n->parent->color = BLACK; 259 | } 260 | else 261 | delete_case5(n); 262 | } 263 | 264 | void delete_case5(rbtree_node n) 265 | { 266 | if (n == n->parent->left && 267 | node_color(sibling(n)) == BLACK && 268 | node_color(sibling(n)->left) == RED && 269 | node_color(sibling(n)->right) == BLACK) 270 | { 271 | sibling(n)->color = RED; 272 | sibling(n)->left->color = BLACK; 273 | rotate_right(sibling(n)); 274 | } 275 | else if (n == n->parent->right && 276 | node_color(sibling(n)) == BLACK && 277 | node_color(sibling(n)->right) == RED && 278 | node_color(sibling(n)->left) == BLACK) 279 | { 280 | sibling(n)->color = RED; 281 | sibling(n)->right->color = BLACK; 282 | rotate_left(sibling(n)); 283 | } 284 | delete_case6(n); 285 | } 286 | 287 | void delete_case6(rbtree_node n) 288 | { 289 | sibling(n)->color = node_color(n->parent); 290 | n->parent->color = BLACK; 291 | if (n == n->parent->left) { 292 | assert (node_color(sibling(n)->right) == RED); 293 | sibling(n)->right->color = BLACK; 294 | rotate_left(n->parent); 295 | } 296 | else 297 | { 298 | assert (node_color(sibling(n)->left) == RED); 299 | sibling(n)->left->color = BLACK; 300 | rotate_right(n->parent); 301 | } 302 | } 303 | }; 304 | } 305 | 306 | #endif 307 | -------------------------------------------------------------------------------- /include/lib/shuffle.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * FISHER YATES'S SHUFFLE 9 | * 10 | * Features: 11 | * 1. shuffle list in O(n) time. 12 | * 13 | * http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle 14 | * 15 | ******************************************************************************/ 16 | 17 | #ifndef __SHUFFLE_H__ 18 | #define __SHUFFLE_H__ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace alg 25 | { 26 | /** 27 | * shuffle the 'list' of length 'len' 28 | */ 29 | template 30 | static void shuffle(T * list, int len) 31 | { 32 | srand(time(NULL)); 33 | int i = len, j; 34 | T temp; 35 | 36 | if ( i == 0 ) return; 37 | while ( --i ) { 38 | j = rand() % (i+1); 39 | temp = list[i]; 40 | list[i] = list[j]; 41 | list[j] = temp; 42 | } 43 | } 44 | } 45 | 46 | #endif // 47 | -------------------------------------------------------------------------------- /include/lib/skip_list.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * SKIP LIST 9 | * 10 | * http://en.wikipedia.org/wiki/Skip_list 11 | * 12 | ******************************************************************************/ 13 | 14 | #ifndef __SKIP_LIST_H__ 15 | #define __SKIP_LIST_H__ 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | namespace alg 23 | { 24 | template 25 | class SkipList 26 | { 27 | private: 28 | struct SkipNode { 29 | KeyT key; // key 30 | ValueT value; // value 31 | SkipNode ** forward; // pointers to different levels 32 | }; 33 | 34 | struct SkipNode * m_header; // the header node, empty 35 | int m_level; // the max level of skip list 36 | 37 | static const int SL_MAX_LEVEL = 6; 38 | 39 | public: 40 | SkipList() 41 | { 42 | m_header = make_node(SL_MAX_LEVEL, 0, 0); 43 | m_level = 0; 44 | } 45 | 46 | ~SkipList() 47 | { 48 | // TODO: free nodes 49 | } 50 | 51 | private: 52 | SkipList(const SkipList &); 53 | SkipList& operator=(const SkipList &); 54 | 55 | public: 56 | /** 57 | * search the given key from the skip list 58 | * if the key is not exist, return NULL 59 | */ 60 | inline ValueT operator[] (KeyT key) const 61 | { 62 | struct SkipNode* x = m_header; 63 | 64 | // travels down until level-0 65 | for(int i = m_level; i >= 0; i--) { 66 | while(x->forward[i] != NULL && x->forward[i]->key < key) { 67 | x = x->forward[i]; 68 | } 69 | } 70 | x = x->forward[0]; 71 | if(x != NULL && x->key == key) 72 | return x->value; 73 | return NULL; 74 | } 75 | 76 | /** 77 | * insert a key->key pair into the list 78 | */ 79 | void insert(KeyT key, ValueT value) 80 | { 81 | struct SkipNode * x = m_header; 82 | struct SkipNode * update[SL_MAX_LEVEL + 1]; 83 | memset(update, 0, SL_MAX_LEVEL + 1); 84 | 85 | // travels down the list until we found a proper node 86 | for(int i = m_level; i >= 0; i--) { 87 | while(x->forward[i] != NULL && x->forward[i]->key < key) { 88 | x = x->forward[i]; 89 | } 90 | update[i] = x; 91 | } 92 | x = x->forward[0]; 93 | 94 | // if it's not the largest key or duplicated key (middle ones) 95 | if(x == NULL || x->key != key) { 96 | int lvl = random_level(); // random promotion 97 | 98 | // for nodes higer than current max level 99 | // make 'header node' as it's prev 100 | if(lvl > m_level) { 101 | for(int i = m_level + 1; i <= lvl; i++) { 102 | update[i] = m_header; 103 | } 104 | m_level = lvl; 105 | } 106 | x = make_node(lvl, key, value); 107 | 108 | // for each node travlling down, relink into the skiplist 109 | for(int i = 0; i <= lvl; i++) { 110 | x->forward[i] = update[i]->forward[i]; 111 | update[i]->forward[i] = x; 112 | } 113 | } 114 | } 115 | 116 | /** 117 | * delete a node by it's key 118 | */ 119 | void delete_key(KeyT key) 120 | { 121 | struct SkipNode* x = m_header; 122 | struct SkipNode* update[SL_MAX_LEVEL + 1]; 123 | memset(update, 0, SL_MAX_LEVEL + 1); 124 | 125 | // find the node, and record it's level update info 126 | for(int i = m_level; i >= 0; i--) { 127 | while(x->forward[i] != NULL && x->forward[i]->key < key) { 128 | x = x->forward[i]; 129 | } 130 | update[i] = x; 131 | } 132 | x = x->forward[0]; 133 | 134 | // delete every level's key 135 | if(x != NULL && x->key == key) { 136 | for(int i = 0; i <= m_level; i++) { 137 | if(update[i]->forward[i] != x) 138 | break; 139 | update[i]->forward[i] = x->forward[i]; 140 | } 141 | free(x); 142 | 143 | while(m_level > 0 && m_header->forward[m_level] == NULL) { 144 | m_level--; 145 | } 146 | } 147 | } 148 | 149 | void print() 150 | { 151 | for(int i=m_level-1;i>=0;i--) { 152 | SkipNode* x = m_header->forward[i]; 153 | printf("{"); 154 | while(x != NULL) { 155 | printf("%d->%d", x->key, x->value); 156 | x = x->forward[i]; 157 | if(x != NULL) 158 | printf(", "); 159 | } 160 | printf("}\n"); 161 | } 162 | } 163 | private: 164 | /** 165 | * normalize to [0.0 1.0] 166 | */ 167 | inline float rand_norm() { return (float) rand() / RAND_MAX; } 168 | 169 | /** 170 | * get the random promote level 171 | */ 172 | int random_level() 173 | { 174 | int lvl = 0; 175 | // the possibility is 1/2 for each level 176 | while(rand_norm() < 0.5f && lvl < SL_MAX_LEVEL) 177 | lvl++; 178 | 179 | return lvl; 180 | } 181 | 182 | /** 183 | * make a node with specified level & key 184 | */ 185 | SkipNode * make_node(int level, KeyT key, ValueT value) 186 | { 187 | SkipNode * n = new SkipNode; 188 | 189 | // the max forward entry for a key is : level + 1 190 | n->forward = new struct SkipNode *[level + 1]; 191 | n->key = key; 192 | n->value = value; 193 | 194 | return n; 195 | } 196 | 197 | }; 198 | } 199 | 200 | #endif // 201 | -------------------------------------------------------------------------------- /include/lib/sol.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * SELF ORGANIZED LINKED-LIST 9 | * 10 | * Features: 11 | * 1. Implementation of MTF (move-to-front) 12 | * 2. Implementation of MAO (move-ahead-one position) 13 | * 3. Based on double linked list 14 | * 15 | * http://en.wikipedia.org/wiki/Self-organizing_list 16 | * 17 | ******************************************************************************/ 18 | 19 | #ifndef __SOL_H__ 20 | #define __SOL_H__ 21 | #include "double_linked_list.h" 22 | 23 | namespace alg 24 | { 25 | /** 26 | * Move a node to the front 27 | */ 28 | static inline void list_mtf(struct list_head *entry, struct list_head *head) 29 | { 30 | if (entry->prev == head) return; 31 | __list_del(entry->prev, entry->next); 32 | __list_add(entry, head, head->next); 33 | } 34 | 35 | 36 | /** 37 | * Move a node ahead one position 38 | */ 39 | static inline void list_mao(struct list_head *entry, struct list_head * head) 40 | { 41 | // if the entry in the 1st position 42 | if (entry->prev == head) return; 43 | struct list_head * prev = entry->prev; 44 | __list_del(entry->prev, entry->next); 45 | __list_add(entry, prev->prev, prev); 46 | } 47 | } 48 | #endif // 49 | -------------------------------------------------------------------------------- /include/lib/stack.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * STACK 9 | * 10 | * Features: 11 | * 1. Stack with capcity 12 | * 13 | * http://en.wikipedia.org/wiki/Stack_(abstract_data_type) 14 | * 15 | ******************************************************************************/ 16 | 17 | #ifndef __STACK_H__ 18 | #define __STACK_H__ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | /** 25 | * Stack has three properties. capacity stands for the maximum number of 26 | * elements stack can hold. Size stands for the current size of the stack and elements 27 | * is the array of elements 28 | */ 29 | template 30 | class Stack 31 | { 32 | private: 33 | class StackEmptyException: public std::exception 34 | { 35 | public: 36 | virtual const char * what() const throw() 37 | { 38 | return "stack is empty"; 39 | } 40 | }; 41 | 42 | class StackIndexOutOfBoundException: public std::exception 43 | { 44 | public: 45 | virtual const char * what() const throw() 46 | { 47 | return "Index out of bound."; 48 | } 49 | }; 50 | 51 | uint32_t m_capacity; // the total capacity 52 | uint32_t m_size; // current stack size 53 | T * m_elements; // the elements 54 | const StackEmptyException exp_empty; 55 | const StackIndexOutOfBoundException exp_ioob; 56 | 57 | public: 58 | /** 59 | * capcity is the maximum elements the stack can hold. 60 | */ 61 | Stack(uint32_t capacity) { 62 | this->m_capacity = capacity; 63 | this->m_size = 0; 64 | this->m_elements = new T[capacity]; 65 | } 66 | 67 | ~Stack() { 68 | delete [] m_elements; 69 | } 70 | 71 | 72 | private: 73 | Stack(const Stack&); 74 | Stack& operator=(const Stack&); 75 | 76 | 77 | public: 78 | /** 79 | * test whether the stack is empty 80 | */ 81 | inline bool is_empty() const { return m_size==0?true:false; } 82 | 83 | /** 84 | * pop stack 85 | */ 86 | inline void pop() 87 | { 88 | if(m_size!=0) m_size--; 89 | return; 90 | } 91 | 92 | /** 93 | * get the top element 94 | */ 95 | inline const T& top() const 96 | { 97 | if (m_size==0) throw exp_empty; 98 | return m_elements[m_size-1]; 99 | } 100 | 101 | /** 102 | * push an element into the stack 103 | * returns false when stack is full. 104 | */ 105 | inline bool push(const T & value) 106 | { 107 | if(m_size==m_capacity) { return false; } 108 | else { 109 | m_elements[m_size++] = value; 110 | return true; 111 | } 112 | } 113 | 114 | /** 115 | * return the stack size count. 116 | */ 117 | inline uint32_t count() const { return m_size; } 118 | 119 | /** 120 | * return value by index 121 | */ 122 | inline const T& operator[] (int idx) const 123 | { 124 | if (idx<0 || idx >= m_capacity) throw exp_ioob; 125 | return m_elements[m_size-1-idx]; 126 | } 127 | }; 128 | 129 | #endif // 130 | -------------------------------------------------------------------------------- /include/lib/undirected_graph.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * UNDIRECTED GRAPH 9 | * 10 | * Features: 11 | * 1. Adjacency List Implementation 12 | * 13 | * http://en.wikipedia.org/wiki/Undirected_graph 14 | * 15 | ******************************************************************************/ 16 | 17 | #ifndef __UNDIRECTED_GRAPH_H__ 18 | #define __UNDIRECTED_GRAPH_H__ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "graph_defs.h" 26 | #include "double_linked_list.h" 27 | 28 | namespace alg 29 | { 30 | class UndirectedGraph:public Graph 31 | { 32 | private: 33 | /** 34 | * delete a vertex from adjacent lists 35 | */ 36 | void delete_me(Adjacent * a) 37 | { 38 | Vertex * v,* vn; 39 | 40 | // for each connected-vertex 41 | list_for_each_entry_safe(v, vn, &a->v_head, v_node){ 42 | Adjacent * neigh = (*this)[v->id]; 43 | neigh->delete_vertex(a->v.id); 44 | num_edges--; 45 | } 46 | } 47 | public: 48 | /** 49 | * create a new vertex and add to the graph, with specified id. 50 | */ 51 | inline bool add_vertex(uint32_t id) 52 | { 53 | if ((*this)[id]!=NULL) return false; 54 | 55 | // new empty adjacent list 56 | Adjacent * a = new Adjacent(id); 57 | INIT_LIST_HEAD(&a->v_head); 58 | list_add_tail(&a->a_node, &a_head); 59 | num_vertex++; 60 | 61 | return true; 62 | } 63 | 64 | /** 65 | * delete a vertex with specified id 66 | */ 67 | void delete_vertex(uint32_t id) 68 | { 69 | Adjacent * a = (*this)[id]; 70 | if (a==NULL) return; 71 | delete_me(a); 72 | 73 | // delete adjacent list itself. 74 | num_vertex--; 75 | list_del(&a->a_node); 76 | delete a; 77 | } 78 | 79 | /** 80 | * add an edge for x<->y 81 | */ 82 | bool add_edge(uint32_t x, uint32_t y, int32_t weight) 83 | { 84 | struct Adjacent * a1 = (*this)[x]; 85 | struct Adjacent * a2 = (*this)[y]; 86 | 87 | if (a1==NULL || a2==NULL) return false; 88 | if (is_adjacent(a1, a2)) return false; 89 | 90 | // create new vertex & add to adjacent list 91 | Vertex * n = new Vertex(y); 92 | n->weight = weight; 93 | list_add_tail(&n->v_node, &a1->v_head); 94 | 95 | n = new Vertex(x); 96 | n->weight = weight; 97 | list_add_tail(&n->v_node, &a2->v_head); 98 | 99 | num_edges++; 100 | a1->num_neigh++; 101 | a2->num_neigh++; 102 | 103 | return true; 104 | } 105 | 106 | /** 107 | * delete an edge for x<->y 108 | */ 109 | void delete_edge(uint32_t x, uint32_t y) 110 | { 111 | Adjacent * a1 = (*this)[x]; 112 | Adjacent * a2 = (*this)[y]; 113 | if (a1==NULL || a2==NULL) return ; 114 | if (!is_adjacent(a1, a2)) return ; 115 | 116 | Vertex * v, *n; 117 | // find x->.....y... 118 | list_for_each_entry_safe(v, n, &a1->v_head, v_node){ 119 | if (v->id == y) { 120 | list_del(&v->v_node); 121 | delete(v); 122 | num_edges--; 123 | a1->num_neigh--; 124 | } 125 | } 126 | 127 | // find y->.....x... 128 | list_for_each_entry_safe(v, n, &a2->v_head, v_node){ 129 | if (v->id == x) { 130 | list_del(&v->v_node); 131 | delete(v); 132 | a2->num_neigh--; 133 | } 134 | } 135 | } 136 | }; 137 | } 138 | 139 | #endif // 140 | -------------------------------------------------------------------------------- /include/lib/universal_hash.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * UNIVERSAL HASH FUNCTION 9 | * 10 | * http://en.wikipedia.org/wiki/Universal_hash 11 | * 12 | ******************************************************************************/ 13 | 14 | #ifndef __UNIVERSAL_HASH_H__ 15 | #define __UNIVERSAL_HASH_H__ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "prime.h" 25 | #include "imath.h" 26 | #include "random.h" 27 | #include "integer.h" 28 | 29 | namespace alg 30 | { 31 | struct UHash { 32 | uint32_t a[KLEN]; 33 | uint32_t prime; 34 | }; 35 | 36 | /** 37 | * init an universal hash struct 38 | */ 39 | static inline void uhash_init(struct UHash * params, uint32_t max_element) 40 | { 41 | int i; 42 | // the size of the hash bucket is the prime larger than 2 * max_element 43 | for(i=max_element+1;;i++) { 44 | if (is_prime(i)) { 45 | params->prime = i; 46 | break; 47 | } 48 | } 49 | 50 | for (i = 0; i < KLEN;i++) { 51 | params->a[i] = rand()%params->prime; 52 | } 53 | } 54 | 55 | /** 56 | * hash a key 57 | */ 58 | static inline uint32_t uhash_integer(const struct UHash * params, uint64_t key) 59 | { 60 | uint32_t k[KLEN]; 61 | uint32_t sum; 62 | 63 | m_based(key, params->prime, k); 64 | sum = dot_product(k,params->a,KLEN); 65 | return sum%params->prime; 66 | } 67 | 68 | /** 69 | * hash an arbitary length integer. 70 | * len, number of 32-bit integer, max len is 32 71 | */ 72 | static uint32_t uhash_bigint(const struct UHash * params, uint32_t * key, uint32_t len) 73 | { 74 | // TODO : need a better algorithm, or NOT? 75 | return key[0]%params->prime; 76 | } 77 | } 78 | #endif // 79 | -------------------------------------------------------------------------------- /include/lib/word_seg.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * DANIEL'S ALGORITHM IMPLEMENTAIONS 3 | * 4 | * /\ | _ _ ._ o _|_ |_ ._ _ _ 5 | * /--\ | (_| (_) | | |_ | | | | | _> 6 | * _| 7 | * 8 | * CHINESE WORD SEGMENTATION 9 | * 10 | * Features: 11 | * 1. based on Hidden Markov Model 12 | * 2. definition the states in B,E,M,S 13 | * 3. solve the hidden states with viterbi algorithm. 14 | * 15 | * http://en.wikipedia.org/wiki/Hidden_Markov_model 16 | * http://en.wikipedia.org/wiki/Viterbi_algorithm 17 | * 18 | ******************************************************************************/ 19 | 20 | #ifndef __WORD_SEG_H__ 21 | #define __WORD_SEG_H__ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "generic.h" 28 | #include "hash_table.h" 29 | #include "queue.h" 30 | 31 | namespace alg 32 | { 33 | /** 34 | * define a word in four state 35 | * which means a 36 | * -- SINGLE, a single word like '地','水','火','风' 37 | * -- BEGIN, a word is the begin of the word, eg '如' in '如果' 38 | * -- MIDDLE, a word is at the middle of the word, eg, '习' in '补习班' 39 | * -- END, a word is at the end of the word, eg, '物' in '有机物' 40 | */ 41 | class WordSeg 42 | { 43 | public: 44 | enum WORDSTATE { 45 | SINGLE = 0, 46 | BEGIN = 1, 47 | MIDDLE = 2, 48 | END = 3 49 | }; 50 | 51 | enum WORDTAG { 52 | N=0, // 名词 53 | V, // 动词 54 | ADJ , // 形容词 55 | ADV , // 副词 56 | CLAS, // 量词 57 | ECHO, // 拟声词 58 | STRU, // 结构助词 59 | AUX , // 助词 60 | COOR, // 并列连词 61 | CONJ, // 连词 62 | SUFFIX, // 前缀 63 | PREFIX, // 后缀 64 | PREP , // 介词 65 | PRON , // 代词 66 | QUES , // 疑问词 67 | NUM , // 数词 68 | IDIOM // 成语 69 | }; 70 | 71 | /** 72 | * the state transition probability matrix. 73 | * the 2-d array is in the format of : 74 | * SINGLE -> S B M E 75 | * ... -> S B M E 76 | */ 77 | inline const float (&TP()const)[4][4] 78 | { 79 | /** 80 | * the state transition probability matrix. 81 | * the 2-d array is in the format of : 82 | * SINGLE -> S B M E 83 | * ... -> S B M E 84 | */ 85 | static const float _TP[4][4] = { 86 | {0.5f, 0.5f, 0.0f, 0.0f}, // S 87 | {0.0f, 0.0f, 0.5f, 0.5f}, // B 88 | {0.0f, 0.0f, 0.5f, 0.5f}, // M 89 | {0.5f, 0.5f, 0.0f, 0.0f} // E 90 | }; 91 | 92 | return _TP; 93 | } 94 | /** 95 | * the start probability of state 96 | */ 97 | inline const float (&SP()const)[4] 98 | { 99 | /** 100 | * the start probability of state 101 | */ 102 | static const float _SP[4] = {0.5f, 0.5f, 0.0f, 0.0f}; 103 | return _SP; 104 | } 105 | /** 106 | * word state definition 107 | * record a single word emission probability in each state 108 | */ 109 | struct WordEP { 110 | float EP[4]; // the emission probability in each state 111 | uint64_t SC[4]; // the count of appearence in each state 112 | WordEP() { 113 | EP[0] = EP[1] = EP[2] = EP[3] = 0.0f; 114 | SC[0] = SC[1] = SC[2] = SC[3] = 0; 115 | } 116 | }; 117 | 118 | static const int GB18030_NR = 70244; 119 | 120 | /** 121 | * The word segmentation structure. 122 | */ 123 | private: 124 | HashTable wordht; // a WORD-> WordEP hashtable 125 | uint32_t words[GB18030_NR]; // every char in GB18030 126 | 127 | public: 128 | WordSeg() : wordht(GB18030_NR){ } 129 | 130 | /** 131 | * init a WordSeg struct by a given file 132 | * format: 133 | * WORD1 ..... 134 | * WORD2 135 | * .... 136 | * WORDN 137 | */ 138 | WordSeg(const char * path):wordht(GB18030_NR) { 139 | FILE * fp; 140 | char word[64]; // the longest word should be less than 64 char 141 | 142 | fp = fopen(path, "r"); 143 | if (fp==NULL) { 144 | perror(__func__); 145 | } else { 146 | while(!feof(fp)) { 147 | fscanf(fp, "%s%*[^\n]", word); 148 | // printf("read %s count %d\n", word, count); 149 | add_word(word); 150 | } 151 | } 152 | fclose(fp); 153 | 154 | calc_all(); 155 | } 156 | 157 | /** 158 | * add a new word to the hashtable 159 | */ 160 | void add_word(const char * word) 161 | { 162 | int i=0; 163 | int len = strlen(word); 164 | int num_char = 0; 165 | 166 | while(word[i]!='\0') { 167 | uint32_t CH; 168 | i+= gb18030_read(word, i, &CH); 169 | num_char++; 170 | 171 | WordEP & wep = wordht[CH]; 172 | 173 | if (i==len && (num_char==1)) { // single word 174 | wep.SC[SINGLE]+=1; 175 | } else { 176 | if (num_char==1) { // begin 177 | wep.SC[BEGIN]+=1; 178 | } else { 179 | if (i==len) { //end 180 | wep.SC[END]+=1; 181 | } else { // otherwise we are in middle 182 | wep.SC[MIDDLE]+=1; 183 | } 184 | } 185 | } 186 | } 187 | }; 188 | 189 | /** 190 | * return the most possible B,E,M,S sequence(FIFO) for a sentence 191 | * using The Viterbi algorithm 192 | * 193 | * you should strip the , . white-spaces first before entering this 194 | * function 195 | */ 196 | Queue * run(const char * str) 197 | { 198 | // the position of string cursor 199 | int pos = 0; 200 | int len = strlen(str); 201 | 202 | double V[len][4]; 203 | uint32_t CH; 204 | 205 | // record the path 206 | char path[4][len+1]; 207 | char newpath[4][len+1]; 208 | memset(path,0, sizeof(path)); 209 | memset(newpath,0, sizeof(newpath)); 210 | 211 | // Initialize base case. the first observation. 212 | int i; 213 | pos = gb18030_read(str, pos, &CH); 214 | 215 | for(i=0; i<4;i++) { 216 | V[0][i] = SP()[i] * wordht[CH].EP[i]; 217 | path[i][0] = i+'0'; 218 | } 219 | 220 | // Run Viterbi for observation > 1 221 | int wc=1; // word count; 222 | while(pos prob_max) { 233 | prob_max = prob; 234 | state_max = k; 235 | } 236 | } 237 | // update the maximum values 238 | V[wc][j] = prob_max; 239 | strcpy(newpath[j], path[state_max]); 240 | newpath[j][wc] = j+'0'; 241 | } 242 | 243 | // path update 244 | for (j=0;j<4;j++) { 245 | strcpy(path[j], newpath[j]); 246 | } 247 | 248 | wc++; 249 | } 250 | 251 | double prob_max = 0; 252 | int state_max = 0; 253 | 254 | for(i=0;i<4;i++) { 255 | if (V[wc-1][i] > prob_max) { 256 | prob_max = V[wc-1][i]; 257 | state_max = i; 258 | } 259 | } 260 | 261 | Queue * q = new Queue(wc); 262 | 263 | i=0; 264 | while(path[state_max][i]!='\0') { 265 | q->enqueue(path[state_max][i]); 266 | i++; 267 | } 268 | 269 | return q; 270 | } 271 | 272 | private: 273 | /** 274 | * calc a single word emission probability by its count in each state 275 | */ 276 | void calc_ep(WordEP & wep) 277 | { 278 | double sum = wep.SC[0]+wep.SC[1]+wep.SC[2]+wep.SC[3]; 279 | wep.EP[SINGLE] = wep.SC[SINGLE]/sum; 280 | wep.EP[BEGIN] = wep.SC[BEGIN]/sum; 281 | wep.EP[END] = wep.SC[END]/sum; 282 | wep.EP[MIDDLE] = wep.SC[MIDDLE]/sum; 283 | }; 284 | 285 | /** 286 | * calculate the emission probability for each word 287 | */ 288 | void calc_all() 289 | { 290 | unsigned char i, j, m, n; 291 | 292 | // for each char in gb18030 293 | for (i=0;i<=0x7f;i++) { calc_ep(wordht[i]); } 294 | 295 | for (i=0x81;i<=0xFE;i++) { 296 | for(j=0x40;j<=0xFE;j++) { 297 | uint32_t CH = (i << 8)|j; 298 | calc_ep(wordht[CH]); 299 | } 300 | 301 | for(j=0x30;j<=0x39;j++) { 302 | for(m=0x81;m<=0xFE;m++) { 303 | for(n=0x30;n<=0x39;n++) { 304 | uint32_t CH = (i<<24)|(j<<16)|(m<<8)|n; 305 | calc_ep(wordht[CH]); 306 | } 307 | } 308 | } 309 | } 310 | }; 311 | }; 312 | 313 | } 314 | #endif // 315 | -------------------------------------------------------------------------------- /include/module.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIBERNET_MODULE_H__ 2 | #define __FIBERNET_MODULE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "context.h" 12 | 13 | #define MAX_MODULE_TYPE 32 14 | 15 | namespace fibernet { 16 | 17 | typedef void * (*fibernet_dl_create)(void); 18 | typedef int (*fibernet_dl_init)(void * inst, Context *, const char * parm); 19 | typedef void (*fibernet_dl_release)(void * inst); 20 | 21 | /** 22 | * Module definition 23 | */ 24 | struct Module { 25 | const char * name; // the name of the module 26 | void * module; // dlopen result, handle 27 | fibernet_dl_create create; // point to create function 28 | fibernet_dl_init init; // point to init function 29 | fibernet_dl_release release; // pointer to release function 30 | 31 | /** 32 | * module create/init/release 33 | */ 34 | void * call_create() 35 | { 36 | if (create) { 37 | return create(); 38 | } else { 39 | return (void *)(intptr_t)(~0); 40 | } 41 | } 42 | 43 | int call_init(void * inst, Context *ctx, const char * parm) 44 | { 45 | return init(inst, ctx, parm); 46 | } 47 | 48 | void call_release(void *inst) 49 | { 50 | if (release) { 51 | release(inst); 52 | } 53 | } 54 | }; 55 | 56 | /** 57 | * Global Modules definition 58 | */ 59 | class GlobalModules { 60 | private: 61 | int m_count; // module count 62 | int m_lock; // lock 63 | const char * m_path; // module path 64 | Module m[MAX_MODULE_TYPE]; // all modules 65 | 66 | static GlobalModules * _instance; 67 | public: 68 | 69 | static void create_instance(const char * path) 70 | { 71 | if (!_instance) _instance = new GlobalModules(path); 72 | } 73 | 74 | static GlobalModules * instance() { return _instance;} 75 | 76 | /** 77 | * query a module 78 | */ 79 | Module * query(const char * name) 80 | { 81 | Module * result = find(name); 82 | if (result) 83 | return result; 84 | 85 | while(__sync_lock_test_and_set(&m_lock,1)) {} 86 | 87 | result = find(name); // double check 88 | 89 | if (result == NULL && m_count < MAX_MODULE_TYPE) { 90 | int index = m_count; 91 | void * dl = try_open(name); 92 | if (dl) { 93 | m[index].name = name; 94 | m[index].module = dl; 95 | 96 | if (open_sym(&m[index]) == 0) { 97 | m[index].name = strdup(name); 98 | m_count ++; 99 | result = &m[index]; 100 | } 101 | } 102 | } 103 | 104 | __sync_lock_release(&m_lock); 105 | 106 | return result; 107 | } 108 | 109 | void insert(Module *mod) 110 | { 111 | while(__sync_lock_test_and_set(&m_lock,1)) {} 112 | 113 | Module * m = find(mod->name); 114 | assert(m == NULL && m_count < MAX_MODULE_TYPE); 115 | int index = m_count; 116 | m[index] = *mod; 117 | ++m_count; 118 | __sync_lock_release(&m_lock); 119 | } 120 | 121 | private: 122 | GlobalModules(const char * path):m_count(0),m_lock(0) { m_path = strdup(path); } 123 | 124 | /** 125 | * try opening a .so 126 | */ 127 | void * try_open(const char * name) 128 | { 129 | const char * path = m_path; 130 | // substitute ? mark, like 131 | // service/?.so 132 | size_t path_size = strlen(path); 133 | size_t name_size = strlen(name); 134 | 135 | int sz = path_size + name_size; 136 | char tmp[sz]; 137 | int i; 138 | for (i=0;path[i]!='?' && path[i]!='\0';i++) { 139 | tmp[i] = path[i]; 140 | } 141 | memcpy(tmp+i,name,name_size); 142 | if (path[i] == '?') { 143 | strcpy(tmp+i+name_size,path+i+1); 144 | } else { 145 | fprintf(stderr,"Invalid C service path\n"); 146 | exit(1); 147 | } 148 | 149 | void * dl = dlopen(tmp, RTLD_NOW | RTLD_GLOBAL); 150 | 151 | if (dl == NULL) { 152 | fprintf(stderr, "try open %s failed : %s\n",tmp,dlerror()); 153 | } 154 | 155 | return dl; 156 | } 157 | 158 | /** 159 | * find a module by name 160 | */ 161 | Module * find(const char * name) 162 | { 163 | int i; 164 | for (i=0;iname); 178 | char tmp[name_size + 9]; // create/init/release , longest name is release (7) 179 | memcpy(tmp, mod->name, name_size); 180 | 181 | strcpy(tmp+name_size, "_create"); 182 | *(void **) (&mod->create) = dlsym(mod->module, tmp); 183 | strcpy(tmp+name_size, "_init"); 184 | *(void **) (&mod->init) = dlsym(mod->module, tmp); 185 | strcpy(tmp+name_size, "_release"); 186 | *(void **) (&mod->release) = dlsym(mod->module, tmp); 187 | 188 | return mod->init == NULL; 189 | } 190 | 191 | 192 | }; 193 | } 194 | 195 | #endif // 196 | -------------------------------------------------------------------------------- /include/monitor.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIBERNET_MONITOR_H__ 2 | #define __FIBERNET_MONITOR_H__ 3 | 4 | namespace fibernet 5 | { 6 | class Monitor 7 | { 8 | private: 9 | int version; 10 | int check_version; 11 | uint32_t m_src; 12 | uint32_t m_des; 13 | 14 | public: 15 | Monitor(): version(0), check_version(0), m_src(0), m_dest(0); 16 | 17 | void trigger(uint32_t src, uint32_t dest) 18 | { 19 | m_src = src; 20 | m_dest= dest; 21 | __sync_fetch_and_add(&version , 1); 22 | } 23 | 24 | void check() 25 | { 26 | if (version == check_version) { 27 | if (m_dest) { 28 | Context::endless(m_dest); 29 | skynet_error(NULL, "A message from [ :%08x ] to [ :%08x ] maybe in an endless loop", m_src, m_dest); 30 | } 31 | } else { 32 | check_version = version; 33 | } 34 | } 35 | }; 36 | } 37 | 38 | #endif // 39 | -------------------------------------------------------------------------------- /include/mq.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIBERNET_MQ_H__ 2 | #define __FIBERNET_MQ_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "fibernet.h" 10 | #include "harbor.h" 11 | 12 | #define DEFAULT_QUEUE_SIZE 64 13 | #define MAX_GLOBAL_MQ 0x10000 14 | 15 | // 0 means mq is not in global mq. 16 | // 1 means mq is in global mq , or the message is dispatching. 17 | // 2 means message is dispatching with locked session set. 18 | // 3 means mq is not in global mq, and locked session has been set. 19 | 20 | #define MQ_IN_GLOBAL 1 21 | #define MQ_DISPATCHING 2 22 | #define MQ_LOCKED 3 23 | 24 | #define GP(p) ((p) % MAX_GLOBAL_MQ) 25 | 26 | namespace fibernet 27 | { 28 | class MQ; 29 | /** 30 | * Global Message Queue 31 | */ 32 | class GlobalMQ { 33 | private: 34 | uint32_t head; 35 | uint32_t tail; 36 | MQ ** queue; 37 | bool * flag; 38 | 39 | static GlobalMQ * _instance; 40 | 41 | private: 42 | GlobalMQ():head(0), tail(0) 43 | { 44 | queue = new MQ*[MAX_GLOBAL_MQ]; 45 | flag = new bool[MAX_GLOBAL_MQ]; 46 | memset(flag, 0, sizeof(bool) * MAX_GLOBAL_MQ); 47 | } 48 | 49 | ~GlobalMQ() 50 | { 51 | delete [] queue; 52 | delete [] flag; 53 | } 54 | 55 | public: 56 | static GlobalMQ * instance() 57 | { 58 | if (!_instance) { 59 | _instance = new GlobalMQ(); 60 | } 61 | 62 | return _instance; 63 | } 64 | 65 | static void release() 66 | { 67 | if (_instance) { delete _instance; } 68 | } 69 | 70 | MQ * pop(void) 71 | { 72 | uint32_t head = head; 73 | uint32_t head_ptr = GP(head); 74 | 75 | if (head_ptr == GP(tail)) { //empty queue 76 | return NULL; 77 | } 78 | 79 | if(!flag[head_ptr]) { 80 | return NULL; 81 | } 82 | 83 | MQ * mq = queue[head_ptr]; 84 | if (!__sync_bool_compare_and_swap(&head, head, head+1)) { 85 | return NULL; 86 | } 87 | 88 | flag[head_ptr] = false; 89 | __sync_synchronize(); 90 | 91 | return mq; 92 | } 93 | 94 | void push(MQ * mq) 95 | { 96 | uint32_t tail = GP(__sync_fetch_and_add(&tail,1)); 97 | queue[tail] = mq; 98 | __sync_synchronize(); 99 | flag[tail] = true; 100 | __sync_synchronize(); 101 | } 102 | }; 103 | 104 | /** 105 | * Message Queue 106 | */ 107 | class MQ 108 | { 109 | public: 110 | 111 | struct Message 112 | { 113 | uint32_t source; 114 | int session; 115 | void * data; 116 | size_t sz; 117 | }; 118 | 119 | private: 120 | 121 | uint32_t m_handle; 122 | int cap; 123 | int head; 124 | int tail; 125 | int m_lock; 126 | int m_release; 127 | int lock_session; 128 | int in_global; 129 | Message *queue; 130 | 131 | public: 132 | 133 | MQ(uint32_t handle) : m_handle(handle), 134 | cap(DEFAULT_QUEUE_SIZE), 135 | head(0), 136 | tail(0), 137 | m_lock(0), 138 | in_global(MQ_IN_GLOBAL), 139 | m_release(0), 140 | lock_session(0) 141 | { 142 | queue = new Message[cap]; 143 | } 144 | 145 | 146 | inline uint32_t handle() { return m_handle;} 147 | 148 | /** 149 | * enter global queue 150 | */ 151 | void pushglobal() { 152 | LOCK(); 153 | assert(in_global); 154 | if (in_global == MQ_DISPATCHING) { 155 | // lock message queue just now. 156 | in_global = MQ_LOCKED; 157 | } 158 | if (lock_session == 0) { 159 | GlobalMQ::instance()->push(this); 160 | in_global = MQ_IN_GLOBAL; 161 | } 162 | UNLOCK(); 163 | } 164 | 165 | /** 166 | * pop out a message 167 | */ 168 | bool pop(Message * message) 169 | { 170 | bool ret = false; 171 | LOCK(); 172 | 173 | if (head != tail) { 174 | *message = queue[head]; 175 | ret = true; 176 | if ( ++head >= cap) { 177 | head = 0; 178 | } 179 | } 180 | 181 | if (ret) { 182 | in_global = 0; 183 | } 184 | 185 | UNLOCK(); 186 | 187 | return ret; 188 | } 189 | 190 | /** 191 | * push a message 192 | */ 193 | void push(const Message * message) 194 | { 195 | assert(message); 196 | LOCK(); 197 | 198 | // detect whether the msg sender is the locker 199 | // if it's the locker's msg, put it in front of the queue. 200 | if (lock_session !=0 && message->session == lock_session) { 201 | pushhead(message); 202 | } else { 203 | // queue the msg 204 | queue[tail] = *message; 205 | if (++tail >= cap) { 206 | tail = 0; 207 | } 208 | 209 | if (head == tail) { 210 | expand(); 211 | } 212 | 213 | // if mq is locked, just leave 214 | if (lock_session == 0) { 215 | if (in_global == 0) { 216 | in_global = MQ_IN_GLOBAL; 217 | GlobalMQ::instance()->push(this); 218 | } 219 | } 220 | } 221 | 222 | UNLOCK(); 223 | } 224 | 225 | /** 226 | * lock the queue by session 227 | */ 228 | void lock(int session) 229 | { 230 | LOCK(); 231 | assert(lock_session == 0); 232 | assert(in_global == MQ_IN_GLOBAL); 233 | in_global = MQ_DISPATCHING; 234 | lock_session = session; 235 | UNLOCK(); 236 | } 237 | 238 | /** 239 | * release procedure, mark->(dispatcher release) 240 | * mark first, later schedule. 241 | */ 242 | void mark_release() 243 | { 244 | assert(m_release == 0); 245 | m_release = 1; 246 | } 247 | 248 | int release() 249 | { 250 | int ret = 0; 251 | LOCK(); 252 | 253 | if (m_release) { 254 | UNLOCK(); 255 | ret = drop_queue(); 256 | } else { 257 | GlobalMQ::instance()->push(this); 258 | UNLOCK(); 259 | } 260 | 261 | return ret; 262 | } 263 | 264 | private: 265 | 266 | ~MQ() 267 | { 268 | delete [] queue; 269 | } 270 | 271 | inline void LOCK() { while (__sync_lock_test_and_set(&m_lock,1)) {} } 272 | inline void UNLOCK() { __sync_lock_release(&m_lock); } 273 | 274 | /** 275 | * queue expanding 276 | */ 277 | void expand() 278 | { 279 | Message * new_queue = new Message[cap*2]; 280 | int i; 281 | for (i=0;ipush(this); 313 | in_global = MQ_IN_GLOBAL; 314 | } else { 315 | assert(in_global == MQ_DISPATCHING); 316 | } 317 | lock_session = 0; 318 | } 319 | 320 | /** 321 | * queue drop 322 | */ 323 | int drop_queue() { 324 | // todo: send message back to message source 325 | struct Message msg; 326 | int s = 0; 327 | while(!pop(&msg)) { 328 | ++s; 329 | int type = msg.sz >> HANDLE_REMOTE_SHIFT; 330 | if (type == PTYPE_MULTICAST) { 331 | assert((msg.sz & HANDLE_MASK) == 0); 332 | skynet_multicast_dispatch((struct skynet_multicast_message *)msg.data, NULL, NULL); 333 | } else { 334 | // make sure data is freed 335 | free(msg.data); 336 | } 337 | } 338 | delete this; 339 | return s; 340 | } 341 | }; 342 | } 343 | 344 | #endif 345 | -------------------------------------------------------------------------------- /include/multicast.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIBERNET_MULTICAST_H__ 2 | #define __FIBERNET_MULTICAST_H__ 3 | 4 | namespace fibernet 5 | { 6 | 7 | class MulticastMessage 8 | { 9 | private: 10 | int m_ref; 11 | const void * m_msg; 12 | size_t m_sz; 13 | uint32_t m_source; 14 | public: 15 | /** 16 | * create a piece of multicast message. 17 | * the msg is malloc-ed by caller, released by this. 18 | */ 19 | MulticastMessage(const void * msg, size_t sz, uint32_t source) 20 | { 21 | m_ref = 0; 22 | m_msg = msg; 23 | m_sz = sz; 24 | m_source = source; 25 | } 26 | 27 | ~MulticastMessage() { free(m_msg); } 28 | 29 | /** 30 | * copy msg 31 | */ 32 | void copy(int copy) 33 | { 34 | int r = __sync_add_and_fetch(&m_ref, copy); 35 | if (r == 0) { delete this; } 36 | } 37 | }; 38 | 39 | class MulticastGroup 40 | { 41 | private: 42 | struct _mc_array { 43 | int cap; 44 | int number; 45 | uint32_t *data; 46 | }; 47 | 48 | _mc_array enter_queue; 49 | _mc_array leave_queue; 50 | int cap; 51 | int number; 52 | uint32_t * data; 53 | 54 | public: 55 | MulticastGroup():cap(0), number(0),data(NULL); 56 | 57 | void enter(uint32_t handle) { push_array(&group->enter_queue, handle); } 58 | void leave(uint32_t handle) { push_array(&group->leave_queue, handle); } 59 | 60 | /** 61 | * cast a message to this group 62 | */ 63 | int cast(Context * from, MulticastMessage *msg) 64 | { 65 | combine_queue(from); 66 | int release = 0; 67 | if (group->number > 0) { 68 | uint32_t source = from->handle(); 69 | msg->copy(number); 70 | int i; 71 | for (i=0;igrab(p); 74 | if (ctx) { 75 | ctx->send(msg, 0 , source, PTYPE_MULTICAST , 0); 76 | ctx->release(); 77 | } else { 78 | leave(p); 79 | ++release; 80 | } 81 | } 82 | } 83 | 84 | msg->copy(msg, -release); 85 | 86 | return number - release; 87 | } 88 | 89 | private: 90 | void push_array(_mc_array * a, uint32_t v) 91 | { 92 | if (a->number >= a->cap) { 93 | a->cap *= 2; 94 | if (a->cap == 0) { 95 | a->cap = 4; 96 | } 97 | a->data = realloc(a->data, a->cap * sizeof(uint32_t)); 98 | } 99 | a->data[a->number++] = v; 100 | } 101 | 102 | int compar_uint(const void *a, const void *b) { 103 | const uint32_t * aa = a; 104 | const uint32_t * bb = b; 105 | return (int)(*aa - *bb); 106 | } 107 | 108 | void combine_queue(Context * from) 109 | { 110 | qsort(this->enter_queue.data, this->enter_queue.number, sizeof(uint32_t), compar_uint); 111 | qsort(this->leave_queue.data, this->leave_queue.number, sizeof(uint32_t), compar_uint); 112 | int i; 113 | int enter = this->enter_queue.number; 114 | uint32_t last = 0; 115 | 116 | int new_size = this->number + enter; 117 | if (new_size > this->cap) { 118 | this->data = realloc(this->data, new_size * sizeof(uint32_t)); 119 | this->cap = new_size; 120 | } 121 | 122 | // combine enter queue 123 | int old_index = this->number - 1; 124 | int new_index = new_size - 1; 125 | for (i= enter - 1;i >=0 ; i--) { 126 | uint32_t handle = this->enter_queue.data[i]; 127 | if (handle == last) 128 | continue; 129 | last = handle; 130 | if (old_index < 0) { 131 | this->data[new_index] = handle; 132 | } else { 133 | uint32_t p = this->data[old_index]; 134 | if (handle == p) 135 | continue; 136 | if (handle > p) { 137 | this->data[new_index] = handle; 138 | } else { 139 | this->data[new_index] = this->data[old_index]; 140 | --old_index; 141 | last = 0; 142 | ++i; 143 | } 144 | } 145 | --new_index; 146 | } 147 | while (old_index >= 0) { 148 | this->data[new_index] = this->data[old_index]; 149 | --old_index; 150 | --new_index; 151 | } 152 | this->enter_queue.number = 0; 153 | 154 | // remove leave queue 155 | old_index = new_index + 1; 156 | new_index = 0; 157 | 158 | int count = new_size - old_index; 159 | 160 | int leave = this->leave_queue.number; 161 | for (i=0;i= new_size) { 163 | count = 0; 164 | break; 165 | } 166 | uint32_t handle = this->leave_queue.data[i]; 167 | uint32_t p = this->data[old_index]; 168 | if (handle == p) { 169 | --count; 170 | ++old_index; 171 | } else if ( handle > p) { 172 | this->data[new_index] = this->data[old_index]; 173 | ++new_index; 174 | ++old_index; 175 | --i; 176 | } else { 177 | skynet_error(from, "Try to remove a none exist handle : %x", handle); 178 | } 179 | } 180 | while (new_index < count) { 181 | this->data[new_index] = this->data[old_index]; 182 | ++new_index; 183 | ++old_index; 184 | } 185 | 186 | this->leave_queue.number = 0; 187 | 188 | this->number = new_index; 189 | } 190 | 191 | }; 192 | } 193 | 194 | #endif // 195 | -------------------------------------------------------------------------------- /include/rwlock.h: -------------------------------------------------------------------------------- 1 | #ifndef __RWLOCK_H__ 2 | #define __RWLOCK_H__ 3 | 4 | namespace fibernet 5 | { 6 | class rwlock 7 | { 8 | private: 9 | int write; 10 | int read; 11 | public: 12 | rwlock():write(0), read(0) { } 13 | 14 | /** 15 | * read lock 16 | */ 17 | inline void rlock() 18 | { 19 | for (;;) { 20 | while(write) { 21 | __sync_synchronize(); 22 | } 23 | 24 | __sync_add_and_fetch(&read,1); 25 | 26 | if (write) { 27 | __sync_sub_and_fetch(&read,1); 28 | } else { 29 | break; 30 | } 31 | } 32 | } 33 | 34 | /** 35 | * write lock 36 | */ 37 | inline void wlock() 38 | { 39 | while (__sync_lock_test_and_set(&write,1)) {} 40 | while(read) { 41 | __sync_synchronize(); 42 | } 43 | } 44 | 45 | /** 46 | * write unlock 47 | */ 48 | inline void wunlock() 49 | { 50 | __sync_lock_release(&write); 51 | } 52 | 53 | /** 54 | * read unlock 55 | */ 56 | inline void runlock() 57 | { 58 | __sync_sub_and_fetch(&read,1); 59 | } 60 | }; 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /include/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIBERNET_TIMER_H__ 2 | #define __FIBERNET_TIMER_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "double_linked_list.h" 10 | 11 | #if defined(__APPLE__) 12 | #include 13 | #endif 14 | 15 | #define TIME_NEAR_SHIFT 8 16 | #define TIME_NEAR (1 << TIME_NEAR_SHIFT) 17 | #define TIME_LEVEL_SHIFT 6 18 | #define TIME_LEVEL (1 << TIME_LEVEL_SHIFT) 19 | #define TIME_NEAR_MASK (TIME_NEAR-1) 20 | #define TIME_LEVEL_MASK (TIME_LEVEL-1) 21 | 22 | namespace fibernet 23 | { 24 | class Timer 25 | { 26 | private: 27 | struct timer_event 28 | { 29 | uint32_t handle; 30 | int session; 31 | }; 32 | 33 | struct timer_node 34 | { 35 | int expire; 36 | struct timer_event event; 37 | list_head node; 38 | }; 39 | 40 | /** 41 | * time is sliced into 5-parts 42 | * |6b|6b|6b|6b|8b| 43 | * for each part, time is hashed into a list of size 2^8 or 2^6 44 | */ 45 | list_head near[TIME_NEAR]; 46 | list_head t[4][TIME_LEVEL-1]; 47 | 48 | int m_lock; 49 | int m_time; 50 | uint32_t m_current; 51 | uint32_t m_starttime; 52 | 53 | static Timer * m_instance; 54 | 55 | public: 56 | static Timer * instance() 57 | { 58 | if (!m_instance) m_instance = new Timer(); 59 | return m_instance; 60 | } 61 | 62 | inline uint32_t gettime_fixsec(void) { return m_starttime; } 63 | inline uint32_t gettime(void) { return m_current; } 64 | 65 | /** 66 | * call this method periodicity to update time. 67 | */ 68 | void updatetime(void) 69 | { 70 | uint32_t ct = _gettime(); 71 | if (ct > m_current) 72 | { 73 | int diff = ct - m_current; // in 10ms 74 | m_current = ct; 75 | int i; 76 | for (i=0;ievent.handle = handle; 97 | node->event.session = session; 98 | 99 | while (__sync_lock_test_and_set(&m_lock,1)) {}; 100 | node->expire = time + m_time; 101 | add_node(node); 102 | __sync_lock_release(&m_lock); 103 | } 104 | 105 | return session; 106 | } 107 | 108 | private: 109 | Timer() 110 | { 111 | int i,j; 112 | for (i=0;iexpire; 166 | int current_time = m_time; 167 | 168 | /** 169 | * near events 170 | */ 171 | if ((time|TIME_NEAR_MASK)==(current_time|TIME_NEAR_MASK)) { 172 | list_add_tail(&node->node, &near[time&TIME_NEAR_MASK]); 173 | } 174 | else { 175 | int i; 176 | int mask=TIME_NEAR << TIME_LEVEL_SHIFT; 177 | for (i=0;i<3;i++) { 178 | if ((time|(mask-1))==(current_time|(mask-1))) { 179 | break; 180 | } 181 | mask <<= TIME_LEVEL_SHIFT; 182 | } 183 | list_add_tail(&node->node, &t[i][((time>>(TIME_NEAR_SHIFT + i*TIME_LEVEL_SHIFT)) & TIME_LEVEL_MASK)-1]); 184 | } 185 | } 186 | 187 | /** 188 | * execute callback 189 | */ 190 | void execute() 191 | { 192 | while (__sync_lock_test_and_set(&m_lock,1)) {}; 193 | 194 | // process near events 195 | int idx = m_time & TIME_NEAR_MASK; 196 | struct timer_node * node, * safe; 197 | list_for_each_entry_safe(node, safe, &near[idx], node) { 198 | struct skynet_message message; 199 | message.source = 0; 200 | message.session = node->event.session; 201 | message.data = NULL; 202 | message.sz = PTYPE_RESPONSE << HANDLE_REMOTE_SHIFT; 203 | 204 | Context::push(t->event.handle, &message); 205 | 206 | list_del(&node->node); 207 | delete t; 208 | } 209 | 210 | ++m_time; // 10ms has passed 211 | 212 | // schedule further events 213 | int msb = TIME_NEAR; // most significant bit 214 | int time = m_time >> TIME_NEAR_SHIFT; // 24bit part 215 | int i=0; 216 | 217 | // for each 6-bit part 218 | while ((m_time & (msb-1))==0) { 219 | idx=time & TIME_LEVEL_MASK; 220 | if (idx!=0) { // ignore 0 221 | --idx; 222 | list_for_each_entry_safe(node,safe,&t[i][idx], node) { 223 | list_del(&node->node); 224 | add_node(node); 225 | } 226 | break; 227 | } 228 | msb <<= TIME_LEVEL_SHIFT; 229 | time >>= TIME_LEVEL_SHIFT; 230 | ++i; 231 | } 232 | __sync_lock_release(&m_lock); 233 | } 234 | }; 235 | } 236 | 237 | #endif // 238 | -------------------------------------------------------------------------------- /src/context.cpp: -------------------------------------------------------------------------------- 1 | #include "context.h" 2 | #include "handle.h" 3 | 4 | namespace fibernet 5 | { 6 | /** 7 | * send message directly to the this context. 8 | */ 9 | void Context::send(void * msg, size_t sz, uint32_t source, int type, int session) 10 | { 11 | MQ::Message smsg; 12 | smsg.source = source; 13 | smsg.session = session; 14 | smsg.data = msg; 15 | smsg.sz = sz | type << HANDLE_REMOTE_SHIFT; 16 | 17 | queue->push(&smsg); 18 | } 19 | 20 | /** 21 | * push a closed-message to a context by handle. 22 | */ 23 | static int Context::push(uint32_t handle, MQ::Message *message) 24 | { 25 | Context * ctx = Handle::instance()->grab(handle); 26 | if (ctx == NULL) { 27 | return -1; 28 | } 29 | ctx->queue->push(message); 30 | ctx->release(); 31 | 32 | return 0; 33 | } 34 | 35 | /** 36 | * set the endless flag for a context by handle. 37 | */ 38 | static void Context::endless(uint32_t handle) 39 | { 40 | Context * ctx = Handle::instance()->grab(handle); 41 | if (ctx == NULL) { 42 | return; 43 | } 44 | ctx->m_endless = true; 45 | ctx->release(); 46 | } 47 | 48 | Context * Context::release() 49 | { 50 | if (__sync_sub_and_fetch(&m_ref,1) == 0) { 51 | _delete_context(); 52 | return NULL; 53 | } 54 | return this; 55 | } 56 | 57 | void Context::_delete_context() 58 | { 59 | mod->call_release(this); 60 | queue->mark_release(); 61 | 62 | delete context; 63 | context_dec(); 64 | } 65 | 66 | /// context factory 67 | static Context * ContextFactory::create(const char * name, const char *param) 68 | { 69 | Module * mod = GlobalModule::instance()->query(name); 70 | 71 | if (mod == NULL) 72 | return NULL; 73 | 74 | void *inst = mod->call_create(); 75 | 76 | if (inst == NULL) 77 | return NULL; 78 | 79 | Context * ctx = new Context; 80 | CHECKCALLING_INIT(ctx) 81 | 82 | ctx->m_mod = mod; 83 | ctx->m_instance = inst; 84 | ctx->m_ref = 2; 85 | ctx->m_cb = NULL; 86 | ctx->m_ud = NULL; 87 | ctx->m_sess_id = 0; 88 | 89 | ctx->m_forward = 0; 90 | ctx->m_init = false; 91 | ctx->m_endless = false; 92 | ctx->m_handle = Handle::instance()->reg(ctx); 93 | 94 | MQ * queue = ctx->queue = new MQ(ctx->handle); 95 | // init function maybe use ctx->handle, so it must init at last 96 | _context_inc(); 97 | 98 | CHECKCALLING_BEGIN(ctx) 99 | int r = mod->call_init(inst, ctx, param); 100 | CHECKCALLING_END(ctx) 101 | if (r == 0) { 102 | Context * ret = ctx->release(); 103 | if (ret) { 104 | ctx->init = true; 105 | } 106 | GlobalMQ::instance()->push(queue); 107 | if (ret) { 108 | printf("[:%x] launch %s %s\n",ret->handle, name, param ? param : ""); 109 | } 110 | return ret; 111 | } else { 112 | ctx->release(); 113 | Handle::instance()->retire(ctx->handle); 114 | return NULL; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/handle.cpp: -------------------------------------------------------------------------------- 1 | #include "handle.h" 2 | 3 | namespace fibernet 4 | { 5 | uint32_t Handle::reg(Context *ctx) 6 | { 7 | uint32_t handle; 8 | 9 | lock.wlock(); 10 | handle = handle_index++; 11 | handle |= m_harbor; 12 | h2c.insert(handle, ctx); 13 | lock.wunlock(); 14 | 15 | ctx->init(handle); 16 | 17 | return handle; 18 | } 19 | 20 | 21 | void Handle::retire(uint32_t handle) 22 | { 23 | Context * ctx = NULL; 24 | 25 | lock.wlock(); 26 | 27 | // delete from h2c 28 | if (h2c.contains(handle)) { 29 | ctx = h2c[handle]; 30 | h2c.delete_key(handle); 31 | } 32 | 33 | // delete from h2n, n2h 34 | std::string name; 35 | if (h2n.contains(handle)) { 36 | name = h2n[handle]; 37 | h2n.delete_key(handle); 38 | n2h.delete_key(name); 39 | } 40 | 41 | lock.wunlock(); 42 | 43 | if(ctx) ctx->release(); 44 | } 45 | 46 | Context * Handle::grab(uint32_t handle) 47 | { 48 | Context * ctx = NULL; 49 | lock.rlock(); 50 | 51 | if(h2c.contains(handle)) { 52 | ctx = h2c[handle]; 53 | ctx->grab(); 54 | } 55 | 56 | lock.runlock(); 57 | 58 | return ctx; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/harbor.cpp: -------------------------------------------------------------------------------- 1 | #include "harbor.h" 2 | #include "context.h" 3 | 4 | namespace fibernet 5 | { 6 | /** 7 | * check result before other ops. 8 | */ 9 | bool Harbor::start(const char * master, const char *local) 10 | { 11 | size_t sz = strlen(master) + strlen(local) + 32; 12 | char args[sz]; 13 | sprintf(args, "%s %s %d",master,local,HARBOR >> HANDLE_REMOTE_SHIFT); 14 | Context * ctx = ContextFactory::create("harbor",args); 15 | if (ctx == NULL) { 16 | return false; 17 | } 18 | REMOTE = ctx; 19 | 20 | return true; 21 | } 22 | 23 | void Harbor::send(struct remote_message *rmsg, uint32_t source, int session); 24 | { 25 | int type = rmsg->sz >> HANDLE_REMOTE_SHIFT; 26 | rmsg->sz &= HANDLE_MASK; 27 | assert(type != PTYPE_SYSTEM && type != PTYPE_HARBOR); 28 | REMOTE->send(rmsg, sizeof(*rmsg) , source, type , session); 29 | } 30 | 31 | void Harbor::reg(struct remote_name *rname) 32 | { 33 | int i; 34 | int number = 1; 35 | for (i=0;iname[i]; 37 | if (!(c >= '0' && c <='9')) { 38 | number = 0; 39 | break; 40 | } 41 | } 42 | assert(number == 0); 43 | REMOTE->send(rname, sizeof(*rname), 0, PTYPE_SYSTEM , 0); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/mq.cpp: -------------------------------------------------------------------------------- 1 | #include "mq.h" 2 | 3 | namespace fibernet 4 | { 5 | --------------------------------------------------------------------------------