/* * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, * and the EPL 1.0 (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ package org.h2.dev.util; import java.util.Iterator; import org.h2.mvstore.DataUtils; /** * A very simple linked list that supports concurrent access. * * @param <K> the key type */ public class ConcurrentLinkedListWithTail<K> { /** * The first entry (if any). */ volatile Entry<K> head; /** * The last entry (if any). */ private volatile Entry<K> tail; /** * Get the first element, or null if none. * * @return the first element */ public K peekFirst() { Entry<K> x = head; return x == null ? null : x.obj; } /** * Get the last element, or null if none. * * @return the last element */ public K peekLast() { Entry<K> x = tail; return x == null ? null : x.obj; } /** * Add an element at the end. * * @param obj the element */ public void add(K obj) { Entry<K> x = new Entry<K>(obj); Entry<K> t = tail; if (t != null) { t.next = x; } tail = x; if (head == null) { head = x; } } /** * Remove the first element, if it matches. * * @param obj the element to remove * @return true if the element matched and was removed */ public boolean removeFirst(K obj) { Entry<K> x = head; if (x == null || x.obj != obj) { return false; } if (head == tail) { tail = x.next; } head = x.next; return true; } /** * Remove the last element, if it matches. * * @param obj the element to remove * @return true if the element matched and was removed */ public boolean removeLast(K obj) { Entry<K> x = head; if (x == null) { return false; } Entry<K> prev = null; while (x.next != null) { prev = x; x = x.next; } if (x.obj != obj) { return false; } if (prev != null) { prev.next = null; } if (head == tail) { head = prev; } tail = prev; return true; } /** * Get an iterator over all entries. * * @return the iterator */ public Iterator<K> iterator() { return new Iterator<K>() { Entry<K> current = head; @Override public boolean hasNext() { return current != null; } @Override public K next() { K x = current.obj; current = current.next; return x; } @Override public void remove() { throw DataUtils.newUnsupportedOperationException("remove"); } }; } /** * An entry in the linked list. */ private static class Entry<K> { final K obj; Entry<K> next; Entry(K obj) { this.obj = obj; } } }