trie.cc
来自「BCAST Implementation for NS2」· CC 代码 · 共 362 行
CC
362 行
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-// Copyright (c) 2001-2003 International Computer Science Institute//// Permission is hereby granted, free of charge, to any person obtaining a// copy of this software and associated documentation files (the "Software")// to deal in the Software without restriction, subject to the conditions// listed in the XORP LICENSE file. These conditions include: you must// preserve this copyright notice, and you cannot mention the copyright// holders in advertising related to the Software without their permission.// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This// notice is a summary of the XORP LICENSE file; the license in that file is// legally binding.#ident "$XORP: xorp/fea/click_elements/trie.cc,v 1.2 2003/03/10 23:20:19 hodson Exp $"#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>const u_long topbit = 0x80000000;const int INVALID = -1;#ifdef CLICK#define speak click_chatter#define newline ""#else#define speak printf#define newline "\n"#endifclass Trie {public: struct Tree { Tree *ptrs[2]; int val; Tree() { ptrs[0] = ptrs[1] = 0; val = INVALID; } }; bool _debug; bool _pretty; Tree _head; Trie() { _debug = true; _pretty = false; } bool empty() { return (0 ==_head.ptrs[0]) && (0 ==_head.ptrs[1]); } void print() { prt(&_head, (char *)""); } void prt(Tree *ptr, char *st) { char result[1024]; if(0 == ptr) { return; } if(INVALID != ptr->val) speak("%#x\t%s" newline, ptr->val, st); sprintf(result, "%s0", st); prt(ptr->ptrs[0], result); sprintf(result, "%s1", st); prt(ptr->ptrs[1], result); } bool insert(u_long address, int mask_length, int val) {#ifdef PARANOIA if(INVALID == val) { speak("insert: Attempt to store an invalid entry" newline); return false; }#endif Tree *ptr = &_head; for(int i = 0; i < mask_length; i++) { int index = (address & topbit) == topbit; address <<= 1; if(0 == ptr->ptrs[index]) { ptr->ptrs[index] = new Tree; if(0 == ptr->ptrs[index]) { if(_debug) speak("insert: new failed" newline); return false; } } ptr = ptr->ptrs[index]; } if(INVALID != ptr->val) { speak("insert: value already assigned" newline); return false; } ptr->val = val; return true; } bool del(u_long address, int mask_length) { return del(&_head, address, mask_length); } bool del(Tree *ptr, u_long address, int mask_length) { if((0 == ptr) && (0 != mask_length)) { if(_debug) speak("del:1 not in table" newline); return false; } int index = (address & topbit) == topbit; address <<= 1; if(0 == mask_length) { if(0 == ptr) { if(_debug) speak("del:1 zero pointer" newline); return false; } if(INVALID == ptr->val) { if(_debug) speak("del:2 not in table" newline); return false; } ptr->val = INVALID; return true; } if(0 == ptr) { if(_debug) speak("del:2 zero pointer" newline); return false; } Tree *next = ptr->ptrs[index]; bool status = del(next, address, --mask_length); if(0 == next) { if(_debug) speak("del: no next pointer" newline); return false; } if((INVALID == next->val) && (0 == next->ptrs[0]) && (0 == next->ptrs[1])) { delete ptr->ptrs[index]; ptr->ptrs[index] = 0; } return status; } int find(u_long address) { Tree *ptr = &_head; Tree *next; int val = INVALID; // The loop should not require bounding. Defensive for(int i = 0; i <= 32; i++) { int index = (address & topbit) == topbit; address <<= 1; if(_pretty) speak("%d", index); val = INVALID != ptr->val ? ptr->val : val; if(0 == (next = ptr->ptrs[index])) { if(_pretty) speak("" newline); return val; } ptr = next; } speak("find: should never happen" newline); return INVALID; }};u_longaddr(char *a){ return ntohl(inet_addr(a));}class Trie f;voidtest1(){ u_long s, startval = addr("128.16.64.16"); int iterate = 1000000; const int start = 20; const int end = 32; const int step = 0x1000; speak("inserting %d routes" newline, iterate * (end - start)); s = startval ; for(int i = 0; i < iterate; i++, s += step) for(int j = start; j < end; j++) if(!f.insert(s, j, s)) { speak("%d %#lx %d" newline, i, s, j); return; } speak("searching for %d routes" newline, iterate * (end - start)); s = startval ; for(int i = 0; i < iterate; i++, s += step) for(int j = start; j < end; j++) if(s != (u_long)f.find(s)) { speak("%d %#lx %d" newline, i, s, j); return; } speak("deleting %d routes" newline, iterate * (end - start)); s = startval; for(int i = 0; i < iterate; i++, s+= step) for(int j = start; j < end; j++) if(!f.del(s, j)) { speak("%#lx %d" newline, s, j); return; }}voidtest2(){ bool failed = false; // Add three routes with different prefix lengths f.insert(addr("128.16.64.16"), 16, 0x16); f.insert(addr("128.16.64.16"), 24, 0x24); f.insert(addr("128.16.64.16"), 32, 0x32); // Find these three routes if(0x32 != f.find(addr("128.16.64.16"))) failed = true; if(0x24 != f.find(addr("128.16.64.17"))) failed = true; if(0x16 != f.find(addr("128.16.65.17"))) failed = true; // Remove the same route twice if(true != f.del(addr("128.16.64.16"), 16)) failed = true; if(false != f.del(addr("128.16.64.16"), 16)) failed = true; // Lookup the routes again. The last route should be missing. if(0x32 != f.find(addr("128.16.64.16"))) failed = true; if(0x24 != f.find(addr("128.16.64.17"))) failed = true; if(INVALID != f.find(addr("128.16.65.17"))) failed = true; // Remove the rest of the routes if(true != f.del(addr("128.16.64.16"), 24)) failed = true; if(true != f.del(addr("128.16.64.16"), 32)) failed = true; if(failed) speak("Tests failed" newline);}voidtest3(){ bool failed = false; f.insert(addr("128.16.64.16"), 16, 0x16); f.insert(addr("128.16.64.16"), 24, 0x24); f.insert(addr("128.16.64.16"), 32, 0x32); f.print(); if(true != f.del(addr("128.16.64.16"), 32)) failed = true; if(true != f.del(addr("128.16.64.16"), 24)) failed = true; if(true != f.del(addr("128.16.64.16"), 16)) failed = true; if(failed) speak("Tests failed" newline);}voidtest4(){ int length = 8; bool failed = false; f.insert(addr("170.16.64.16"), length, length); f.print(); if(true != f.del(addr("170.16.64.16"), length)) failed = true; if(failed) speak("Tests failed" newline);}intmain(){ /* ** Every test should leave the table empty */ test1(); test2(); test3(); test4(); if(false == f.empty()) { speak("Failure the tree is not empty"newline); f.print(); } return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?