/** * Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.linkedin.pinot.transport.common; import java.util.AbstractQueue; import java.util.Collection; import java.util.Deque; import java.util.Iterator; import java.util.NoSuchElementException; /** * Taken from R2's LinkedDeque implementation to be used in Pool implementation. The class is copied as the corresponding R2 jar pulls in a lot of unnecessary jars. * * This class provides the ability to remove an arbitrary interior element (neither head nor tail) * from the queue in O(1) time, by invoking #removeNode(com.linkedin.r2.util.LinkedDeque.Node). * No class in the Java Collections framework provides this ability. * * Adding to and removing from head or tail also run in O(1) time, as expected. * * External synchronization is required! * * @param <T> Resource to be managed by queue */ public class LinkedDequeue<T> extends AbstractQueue<T> implements Deque<T> { public static class Node<T> { private final T _value; private Node<T> _next; private Node<T> _prev; private Node(T value) { _value = value; } } private Node<T> _head; private Node<T> _tail; private int _size; /** * Construct a new instance. */ public LinkedDequeue() { super(); } /** * Construct a new instance, adding all objects in the specified collection. * * @param collection a {@link Collection} of objects to be added. */ public LinkedDequeue(Collection<? extends T> collection) { super(); addAll(collection); } /** * Add a new item at the head of the queue. * * @param item the item to be added. * @return the {@link Node} of the newly added item. */ public Node<T> addFirstNode(T item) { return addBeforeNode(_head, item); } /** * Add a new item at the tail of the queue. * * @param item the item to be added. * @return the {@link Node} of the newly added item. */ public Node<T> addLastNode(T item) { return addBeforeNode(null, item); } /** * Add a new item before the specified Node. * * @param before the {@link Node} before which the item should be added. * @param item the item to be added. * @return the {@link Node} of the newly added item. */ public Node<T> addBeforeNode(Node<T> before, T item) { if (item == null) { throw new NullPointerException(); } if (before != null && before != _head && before._next == null && before._prev == null) { throw new IllegalStateException("node was already removed"); } Node<T> node = new Node<T>(item); if (before == null) { // Adding to tail node._next = null; node._prev = _tail; if (_tail != null) { _tail._next = node; } _tail = node; if (_head == null) { _head = node; } } else { node._next = before; node._prev = before._prev; before._prev = node; if (before == _head) { _head = node; } } _size++; return node; } /** * Remove the specified Node from the queue. * * @param node the Node to be removed. * @return the item contained in the Node which was removed. */ public T removeNode(Node<T> node) { // TODO what if the node is from the wrong list?? if (node != _head && node._next == null && node._prev == null) { // the node has already been removed return null; } if (node == _head) { _head = node._next; } if (node._prev != null) { node._prev._next = node._next; } if (node == _tail) { _tail = node._prev; } if (node._next != null) { node._next._prev = node._prev; } node._next = null; node._prev = null; _size--; return node._value; } // Remaining methods implement Deque<T> @Override public boolean offerFirst(T t) { addFirstNode(t); return true; } @Override public boolean offerLast(T t) { addLastNode(t); return true; } @Override public T peekFirst() { if (_head == null) { return null; } return _head._value; } @Override public T peekLast() { if (_tail == null) { return null; } return _tail._value; } @Override public T pollFirst() { if (_head == null) { return null; } return removeNode(_head); } @Override public T pollLast() { if (_tail == null) { return null; } return removeNode(_tail); } @Override public int size() { return _size; } @Override public Iterator<T> iterator() { return new LinkedQueueIterator(Direction.ASCENDING); } @Override public Iterator<T> descendingIterator() { return new LinkedQueueIterator(Direction.DESCENDING); } private enum Direction { ASCENDING, DESCENDING } private class LinkedQueueIterator implements Iterator<T> { private final Direction _dir; private Node<T> _index; private Node<T> _last; private LinkedQueueIterator(Direction dir) { _dir = dir; _index = _dir == Direction.ASCENDING ? _head : _tail; } @Override public boolean hasNext() { return _index != null; } @Override public T next() { if (_index == null) { throw new NoSuchElementException(); } _last = _index; T value = _index._value; _index = _dir == Direction.ASCENDING ? _index._next : _index._prev; return value; } @Override public void remove() { if (_last == null) { throw new IllegalStateException(); } removeNode(_last); _last = null; } } @Override public void addFirst(T e) { if (!offerFirst(e)) { throw new IllegalStateException("Queue full"); } } @Override public void addLast(T e) { if (!offerLast(e)) { throw new IllegalStateException("Queue full"); } } @Override public T removeFirst() { T e = pollFirst(); if (e == null) { throw new NoSuchElementException(); } return e; } @Override public T removeLast() { T e = pollLast(); if (e == null) { throw new NoSuchElementException(); } return e; } @Override public T getFirst() { T e = peekFirst(); if (e == null) { throw new NoSuchElementException(); } return e; } @Override public T getLast() { T e = peekLast(); if (e == null) { throw new NoSuchElementException(); } return e; } @Override public boolean removeFirstOccurrence(Object o) { for (Iterator<T> i = iterator(); i.hasNext();) { if (i.next().equals(o)) { i.remove(); return true; } } return false; } @Override public boolean removeLastOccurrence(Object o) { for (Iterator<T> i = descendingIterator(); i.hasNext();) { if (i.next().equals(o)) { i.remove(); return true; } } return false; } @Override public void push(T e) { addFirst(e); } @Override public T pop() { return removeFirst(); } // java.util.Queue methods @Override public boolean offer(T e) { return offerLast(e); } @Override public T poll() { return pollFirst(); } @Override public T peek() { return peekFirst(); } }