/* * 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. * Internally, it uses immutable objects. * It uses recursion and is not meant for long lists. * * @param <K> the key type */ public class ConcurrentLinkedList<K> { /** * The sentinel entry. */ static final Entry<?> NULL = new Entry<Object>(null, null); /** * The head entry. */ @SuppressWarnings("unchecked") volatile Entry<K> head = (Entry<K>) NULL; /** * Get the first element, or null if none. * * @return the first element */ public K peekFirst() { Entry<K> x = head; return x.obj; } /** * Get the last element, or null if none. * * @return the last element */ public K peekLast() { Entry<K> x = head; while (x != NULL && x.next != NULL) { x = x.next; } return x.obj; } /** * Add an element at the end. * * @param obj the element */ public synchronized void add(K obj) { head = Entry.append(head, obj); } /** * Remove the first element, if it matches. * * @param obj the element to remove * @return true if the element matched and was removed */ public synchronized boolean removeFirst(K obj) { if (head.obj != obj) { return false; } head = head.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 synchronized boolean removeLast(K obj) { if (peekLast() != obj) { return false; } head = Entry.removeLast(head); 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, Entry<K> next) { this.obj = obj; this.next = next; } @SuppressWarnings("unchecked") static <K> Entry<K> append(Entry<K> list, K obj) { if (list == NULL) { return new Entry<K>(obj, (Entry<K>) NULL); } return new Entry<K>(list.obj, append(list.next, obj)); } @SuppressWarnings("unchecked") static <K> Entry<K> removeLast(Entry<K> list) { if (list == NULL || list.next == NULL) { return (Entry<K>) NULL; } return new Entry<K>(list.obj, removeLast(list.next)); } } }