/* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.btrace.util; import java.util.ArrayList; import java.util.Collection; import java.util.concurrent.atomic.AtomicInteger; /** * AVL tree based map implementation for <b>long</b> values as keys * @author Jaroslav Bachorik * @param <T> The value type */ final public class LongMap<T> { private final static class Node<T> { private final long id; private final T load; private Node<T> left, right, parent; private int balance = 0; public Node(long id, T load) { this.id = id; this.load = load; } private boolean isLeaningLeft() { return balance >= 1; } private boolean isLeaningRight() { return balance <= -1; } @Override public String toString() { return "Node{" + "id=" + id + ", load=" + load + ", balance=" + balance + '}'; } } public int length = 0; private Node<T> root = null; public void put(long id, T load) { if (root == null) { root = new Node<T>(id, load); length = 1; return; } Node<T> p = findParent(root, id); if (p != null) { if (id <= p.id) { addLeft(p, new Node<T>(id, load)); } else { addRight(p, new Node<T>(id, load)); } length++; } } public T get(long id) { Node<T> n = findNode(root, id); return n != null ? n.load : null; } public T remove(long id) { Node<T> n = findNode(root, id); if (n != null) { removeNode(n); } if (n != null) length--; return n != null ? n.load : null; } public Collection<T> values() { Collection<T> coll = new ArrayList<T>(); collect(root, coll); return coll; } private void collect(Node<T> root, Collection<T> coll) { if (root == null) return; collect(root.left, coll); coll.add(root.load); collect(root.right, coll); } private Node<T> findNode(Node<T> n, long id) { if (n == null) return null; if (id == n.id) return n; if (id <= n.id) { return findNode(n.left, id); } else { return findNode(n.right, id); } } private Node<T> findParent(Node<T> root, long id) { if (id <= root.id) { return root.left == null ? root : findParent(root.left, id); } else { return root.right == null ? root : findParent(root.right, id); } } private void addLeft(Node<T> p, Node<T> n) { p.left = n; n.parent = p; balanceLeft(p, n); } private void balance(Node<T> n) { if (n == null) return; Node<T> p = n.parent; if (p != null) { if (p.left == n) { balanceLeft(p, n); } else { balanceRight(p, n); } } } private void balanceLeft(Node<T> p, Node<T> n) { if (p.isLeaningLeft()) { if (n.isLeaningRight()) { rotateLeft(n); } rotateRight(p); return; } if (p.isLeaningRight()) { p.balance = 0; return; } p.balance = 1; balance(p); } private void addRight(Node<T> p, Node<T> n) { p.right = n; n.parent = p; balanceRight(p, n); } private void balanceRight(Node<T> p, Node<T> n) { if (p.isLeaningRight()) { if (n.isLeaningLeft()) { rotateRight(n); } rotateLeft(p); return; } if (p.isLeaningLeft()) { p.balance = 0; return; } p.balance = -1; balance(p); } private void rotateRight(Node<T> n) { Node<T> tmp = n.left; n.left = tmp.right; if (tmp.right != null) { tmp.right.parent = n; } tmp.right = n; tmp.parent = n.parent; if (n.parent != null) { if (n.parent.left == n) { n.parent.left = tmp; } else { n.parent.right = tmp; } } else { root = tmp; } n.parent = tmp; tmp.balance = 0; n.balance = 0; } private void rotateLeft(Node<T> n) { Node<T> tmp = n.right; n.right = tmp.left; if (tmp.left != null) { tmp.left.parent = n; } tmp.left = n; tmp.parent = n.parent; if (n.parent != null) { if (n.parent.left == n) { n.parent.left = tmp; } else { n.parent.right = tmp; } } else { root = tmp; } n.parent = tmp; tmp.balance = 0; n.balance = 0; } private void removeNode(Node<T> n) { Node<T> z = null; if ((n.left == null && n.right == null) || (n.left != null && n.right == null) || (n.left == null && n.right != null)) { z = n; } else { Node<T> y = findMax(n.left); if (y == n.left) { y = findMin(n.right); } Node<T> yr = y.right; Node<T> yl = y.left; Node<T> yp = y.parent; y.right = n.right; y.right.parent = y; y.left = n.left; y.left.parent = y; y.parent = n.parent; if (n.parent != null) { if (n.parent.left == n) { y.parent.left = y; } else { y.parent.right = y; } } else { root = y; } n.left = yl; if (yl != null) { n.left.parent = n; } n.right = yr; if (yr != null) { n.right.parent = n; } n.parent = yp; if (yp.left == y) { yp.left = n; } else { yp.right = n; } z = n; } Node<T> p = z.parent; if (z.left == null && z.right == null) { if (p == null) { root = null; } else { if (p.left == z) { p.left = null; } else { p.right = null; } } } else { if (z.left != null) { if (p == null) { root = z.left; } else { if (p.left == z) { p.left = z.left; z.left.parent = p; } else { p.right = z.left; z.left.parent = p; } } } if (z.right != null) { if (p == null) { root = z.right; } else { if (p.left == z) { p.left = z.right; z.right.parent = p; } else { p.right = z.right; z.right.parent = p; } } } } if (p != null) { rebalanceRemoval(p); } } private Node<T> findMax(Node<T> root) { return root.right == null ? root : findMax(root.right); } private Node<T> findMin(Node<T> root) { return root.left == null ? root : findMin(root.left); } private void rebalanceRemoval(Node<T> n) { Node<T> p = n.parent; if (p == null) { return; } if (p.right == n) { if (p.isLeaningLeft()) { Node<T> s = p.left; int b = s.balance; if (s.isLeaningRight()) { rotateLeft(s); } rotateRight(p); if (b == 0) return; } if (p.balance == 0) { p.balance = 1; return; } p.balance = 0; } else { if (p.isLeaningRight()) { Node<T> s = p.right; int b = s.balance; if (s.isLeaningLeft()) { rotateRight(s); } rotateLeft(p); if (b == 0) return; } if (p.balance == 0) { p.balance = -1; return; } p.balance = 0; } rebalanceRemoval(p); } long[] dump() { if (root == null) return new long[0]; long[] arr = new long[length]; AtomicInteger pos = new AtomicInteger(0); dump(root, arr, pos); return arr; } private void dump(Node<T> n, long[] arr, AtomicInteger pos) { if (n.left != null) { dump(n.left, arr, pos); } arr[pos.getAndIncrement()] = n.id; if (n.right != null) { dump(n.right, arr, pos); } } }