/* * Copyright (c) 2011, 2012 Eike Stepper (Berlin, Germany) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Eike Stepper - initial API and implementation */ package org.eclipse.net4j.util.collection; /** * @author Eike Stepper * @since 3.2 */ public abstract class ConcurrentArray<E> { protected E[] elements; private final E[] EMPTY = newArray(0); public ConcurrentArray() { } public boolean isEmpty() { return elements == null; // Atomic operation } /** * Returns the elements, never <code>null</code>. */ public E[] get() { E[] result = elements; // Atomic operation return result == null ? EMPTY : result; } public synchronized void add(E element) { if (!validate(element)) { return; } if (elements == null) { E[] array = newArray(1); array[0] = element; elements = array; firstElementAdded(); } else { int length = elements.length; E[] array = newArray(length + 1); System.arraycopy(elements, 0, array, 0, length); array[length] = element; elements = array; } } public synchronized boolean remove(E element) { if (elements != null) { int length = elements.length; if (length == 1) { if (elements[0] == element) { elements = null; lastElementRemoved(); return true; } } else { for (int i = 0; i < length; i++) { E e = elements[i]; if (e == element) { E[] array = newArray(length - 1); if (i > 0) { System.arraycopy(elements, 0, array, 0, i); } if (i + 1 <= length - 1) { System.arraycopy(elements, i + 1, array, i, length - 1 - i); } elements = array; return true; } } } } return false; } /** * Synchronized through {@link #add(Object)}. */ protected boolean validate(E element) { return true; } /** * Synchronized through {@link #add(Object)}. */ protected void firstElementAdded() { } /** * Synchronized through {@link #remove(Object)}. */ protected void lastElementRemoved() { } /** * Synchronized through {@link #add(Object)} or {@link #remove(Object)}. */ protected abstract E[] newArray(int length); /** * @author Eike Stepper */ public abstract static class Unique<E> extends ConcurrentArray<E> { public Unique() { } @Override protected boolean validate(E element) { if (elements != null) { for (int i = 0; i < elements.length; i++) { if (equals(element, elements[i])) { violatingUniqueness(element); return false; } } } return true; } /** * Synchronized through {@link #add(Object)}. */ protected boolean equals(E e1, E e2) { return e1 == e2; } /** * Synchronized through {@link #add(Object)}. */ protected void violatingUniqueness(E element) { } } /** * @author Eike Stepper */ public abstract static class DuplicateCounter<E> extends ConcurrentArray<E> { private int maxDuplicates; public DuplicateCounter() { } public final int getMaxDuplicates() { return maxDuplicates; } @Override protected boolean validate(E element) { if (elements != null) { int duplicates = 0; for (int i = 0; i < elements.length; i++) { if (equals(element, elements[i])) { ++duplicates; } } if (duplicates > maxDuplicates) { maxDuplicates = duplicates; } } return true; } protected boolean equals(E e1, E e2) { return e1 == e2; } } }