/* * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * Copyright (C) 2012 Kristian S. Stangeland * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program 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 for more details. * * You should have received a copy of the GNU General Public License along with this program; * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA */ package com.comphenix.protocol.concurrency; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import com.google.common.base.Objects; import com.google.common.collect.Iterables; /** * An implicitly sorted array list that preserves insertion order and maintains duplicates. * @param - type of the elements in the list. */ public class SortedCopyOnWriteArray> implements Iterable, Collection { // Prevent reordering private volatile List list; /** * Construct an empty sorted array. */ public SortedCopyOnWriteArray() { list = new ArrayList(); } /** * Create a sorted array from the given list. The elements will be automatically sorted. * @param wrapped - the collection whose elements are to be placed into the list. */ public SortedCopyOnWriteArray(Collection wrapped) { this.list = new ArrayList(wrapped); } /** * Create a sorted array from the given list. * @param wrapped - the collection whose elements are to be placed into the list. * @param sort - TRUE to automatically sort the collection, FALSE if it is already sorted. */ public SortedCopyOnWriteArray(Collection wrapped, boolean sort) { this.list = new ArrayList(wrapped); if (sort) { Collections.sort(list); } } /** * Inserts the given element in the proper location. * @param value - element to insert. */ @Override public synchronized boolean add(T value) { // We use NULL as a special marker, so we don't allow it if (value == null) throw new IllegalArgumentException("value cannot be NULL"); List copy = new ArrayList(); for (T element : list) { // If the value is now greater than the current element, it should be placed right before it if (value != null && value.compareTo(element) < 0) { copy.add(value); value = null; } copy.add(element); } // Don't forget to add it if (value != null) copy.add(value); list = copy; return true; } @Override public synchronized boolean addAll(Collection values) { if (values == null) throw new IllegalArgumentException("values cannot be NULL"); if (values.size() == 0) return false; List copy = new ArrayList(); // Insert the new content and sort it copy.addAll(list); copy.addAll(values); Collections.sort(copy); list = copy; return true; } /** * Removes from the list by making a new list with every element except the one given. *

* Objects will be compared using the given objects equals() method. * @param value - value to remove. */ @Override public synchronized boolean remove(Object value) { List copy = new ArrayList(); // Note that there's not much to be gained from using BinarySearch, as we // have to copy (and thus read) the entire list regardless. // Copy every element except the one given to us. for (T element : list) { if (value != null && !Objects.equal(value, element)) { copy.add(element); value = null; } } list = copy; return value == null; } @Override public boolean removeAll(Collection values) { // Special cases if (values == null) throw new IllegalArgumentException("values cannot be NULL"); if (values.size() == 0) return false; List copy = new ArrayList(); copy.addAll(list); copy.removeAll(values); list = copy; return true; } @Override public boolean retainAll(Collection values) { // Special cases if (values == null) throw new IllegalArgumentException("values cannot be NULL"); if (values.size() == 0) return false; List copy = new ArrayList(); copy.addAll(list); copy.removeAll(values); list = copy; return true; } /** * Removes from the list by making a copy of every element except the one with the given index. * @param index - index of the element to remove. */ public synchronized void remove(int index) { List copy = new ArrayList(list); copy.remove(index); list = copy; } /** * Retrieves an element by index. * @param index - index of element to retrieve. * @return The element at the given location. */ public T get(int index) { return list.get(index); } /** * Retrieve the size of the list. * @return Size of the list. */ public int size() { return list.size(); } /** * Retrieves an iterator over the elements in the given list. * Warning: No not attempt to remove elements using the iterator. */ public Iterator iterator() { return Iterables.unmodifiableIterable(list).iterator(); } @Override public void clear() { list = new ArrayList(); } @Override public boolean contains(Object value) { return list.contains(value); } @Override public boolean containsAll(Collection values) { return list.containsAll(values); } @Override public boolean isEmpty() { return list.isEmpty(); } @Override public Object[] toArray() { return list.toArray(); } @SuppressWarnings("hiding") @Override public T[] toArray(T[] a) { return list.toArray(a); } }