| package net.floodlightcontroller.bgproute; |
| |
| public class Ptree { |
| int maxKeyBits; |
| int maxKeyOctets; |
| int refCount; |
| PtreeNode top; |
| byte maskBits[] = { (byte)0x00, (byte)0x80, (byte)0xc0, (byte)0xe0, (byte)0xf0, (byte)0xf8, (byte)0xfc, (byte)0xfe, (byte)0xff }; |
| |
| // Constructor. |
| Ptree(int max_key_bits) { |
| maxKeyBits = max_key_bits; |
| maxKeyOctets = bit_to_octet(max_key_bits); |
| refCount = 0; |
| } |
| |
| public PtreeNode acquire(byte [] key) { |
| return acquire(key, maxKeyBits); |
| } |
| |
| public PtreeNode acquire(byte [] key, int key_bits) { |
| if (key_bits > maxKeyBits) { |
| return null; |
| } |
| |
| PtreeNode node = top; |
| PtreeNode match = null; |
| |
| while (node != null |
| && node.keyBits <= key_bits |
| && key_match(node.key, node.keyBits, key, key_bits) == true) { |
| if (node.keyBits == key_bits) { |
| return addReference(node); |
| } |
| |
| match = node; |
| |
| if (bit_check(key, node.keyBits) == true) { |
| node = node.right; |
| } else { |
| node = node.left; |
| } |
| } |
| |
| PtreeNode add = null; |
| |
| if (node == null) { |
| add = new PtreeNode(key, key_bits, maxKeyOctets); |
| |
| if (match != null) { |
| node_link(match, add); |
| } else { |
| top = add; |
| } |
| } else { |
| add = node_common(node, key, key_bits); |
| if (add == null) { |
| return null; |
| } |
| |
| if (match != null) { |
| node_link(match, add); |
| } else { |
| top = add; |
| } |
| node_link(add, node); |
| |
| if (add.keyBits != key_bits) { |
| match = add; |
| |
| add = new PtreeNode(key, key_bits, maxKeyOctets); |
| node_link(match, add); |
| } |
| } |
| |
| return addReference(add); |
| } |
| |
| public PtreeNode lookup(byte [] key, int key_bits) { |
| if (key_bits > maxKeyBits) { |
| return null; |
| } |
| |
| PtreeNode node = top; |
| |
| while (node != null |
| && node.keyBits <= key_bits |
| && key_match(node.key, node.keyBits, key, key_bits) == true) { |
| if (node.keyBits == key_bits) { |
| return addReference(node); |
| } |
| |
| if (bit_check(key, node.keyBits) == true) { |
| node = node.right; |
| } else { |
| node = node.left; |
| } |
| } |
| return null; |
| } |
| |
| public PtreeNode match(byte [] key, int key_bits) { |
| if (key_bits > maxKeyBits) { |
| return null; |
| } |
| PtreeNode node = top; |
| PtreeNode matched = null; |
| |
| if(node!=null) |
| |
| while (node != null |
| && node.keyBits <= key_bits |
| && key_match(node.key, node.keyBits, key, key_bits) == true) { |
| matched = node; |
| |
| if (bit_check(key, node.keyBits) == true) { |
| node = node.right; |
| } else { |
| node = node.left; |
| } |
| } |
| |
| if (matched != null) { |
| return addReference(matched); |
| } |
| |
| return null; |
| } |
| |
| public PtreeNode begin() { |
| if (top == null) { |
| return null; |
| } |
| return addReference(top); |
| } |
| |
| public PtreeNode next(PtreeNode node) { |
| PtreeNode next; |
| |
| if (node.left != null) { |
| next = node.left; |
| addReference(next); |
| delReference(node); |
| return next; |
| } |
| if (node.right != null) { |
| next = node.right; |
| addReference(next); |
| delReference(node); |
| return next; |
| } |
| |
| PtreeNode start = node; |
| while (node.parent != null) { |
| if (node.parent.left == node && node.parent.right != null) { |
| next = node.parent.right; |
| addReference(next); |
| delReference(start); |
| return next; |
| } |
| node = node.parent; |
| } |
| |
| delReference(start); |
| |
| return null; |
| } |
| |
| static public int bit_to_octet(int key_bits) { |
| return Math.max((key_bits + 7) / 8, 1); |
| } |
| |
| private PtreeNode addReference(PtreeNode node) { |
| node.refCount++; |
| return node; |
| } |
| |
| public void delReference(PtreeNode node) { |
| if (node.refCount > 0) { |
| node.refCount--; |
| } |
| if (node.refCount == 0) { |
| node_remove(node); |
| } |
| } |
| |
| private boolean key_match(byte [] key1, int key1_len, byte [] key2, int key2_len) { |
| int offset; |
| int shift; |
| |
| if (key1_len > key2_len) { |
| return false; |
| } |
| |
| offset = (Math.min(key1_len, key2_len)) / 8; |
| shift = (Math.min(key1_len, key2_len)) % 8; |
| |
| if (shift != 0) { |
| if ((maskBits[shift] & (key1[offset] ^ key2[offset])) != 0) { |
| return false; |
| } |
| } |
| |
| while (offset != 0) { |
| offset--; |
| if (key1[offset] != key2[offset]) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| private boolean bit_check(byte [] key, int key_bits) { |
| int offset = key_bits / 8; |
| int shift = 7 - (key_bits % 8); |
| int bit = key[offset] & 0xff; |
| |
| bit >>= shift; |
| |
| if ((bit & 1) == 1) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| private void node_link(PtreeNode node, PtreeNode add) { |
| boolean bit = bit_check(add.key, node.keyBits); |
| |
| if (bit == true) { |
| node.right = add; |
| } else { |
| node.left = add; |
| } |
| add.parent = node; |
| } |
| |
| @SuppressWarnings("unused") |
| private PtreeNode node_common(PtreeNode node, byte [] key, int key_bits) { |
| int i; |
| int limit = Math.min(node.keyBits, key_bits) / 8; |
| |
| for (i = 0; i < limit; i++) { |
| if (node.key[i] != key[i]) { |
| break; |
| } |
| } |
| |
| int common_len = i * 8; |
| int boundary = 0; |
| |
| if (common_len != key_bits) { |
| byte diff = (byte)(node.key[i] ^ key[i]); |
| byte mask = (byte)0x80; |
| int shift_mask = 0; |
| |
| while (common_len < key_bits && ((mask & diff) == 0)) { |
| boundary = 1; |
| |
| shift_mask = (mask & 0xff); |
| shift_mask >>= 1; |
| mask = (byte)shift_mask; |
| |
| common_len++; |
| } |
| } |
| |
| PtreeNode add = new PtreeNode(null, common_len, maxKeyOctets); |
| if (add == null) |
| return null; |
| |
| int j; |
| for (j = 0; j < i; j++) |
| add.key[j] = node.key[j]; |
| |
| if (boundary != 0) |
| add.key[j] = (byte)(node.key[j] & maskBits[add.keyBits % 8]); |
| |
| return add; |
| } |
| |
| private void node_remove(PtreeNode node) { |
| PtreeNode child; |
| PtreeNode parent; |
| |
| if (node.left != null && node.right != null) { |
| return; |
| } |
| |
| if (node.left != null) { |
| child = node.left; |
| } else { |
| child = node.right; |
| } |
| |
| parent = node.parent; |
| |
| if (child != null) { |
| child.parent = parent; |
| } |
| |
| if (parent != null) { |
| if (parent.left == node) { |
| parent.left = child; |
| } else { |
| parent.right = child; |
| } |
| } else { |
| top = child; |
| } |
| |
| if (parent != null && parent.refCount == 0) { |
| node_remove(parent); |
| } |
| } |
| } |