zcommon/src/main/java/org/zkoss/util/FastReadArray.java

Summary

Maintainability
A
25 mins
Test Coverage
/* FastReadArray.java

    Purpose:
        
    Description:
        
    History:
        Tue Jun 17 19:19:19     2008, Created by tomyeh

Copyright (C) 2008 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
    This program is distributed under LGPL Version 2.1 in the hope that
    it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.util;

import java.util.List;
import java.util.LinkedList;
import java.lang.reflect.Array;

import org.zkoss.lang.Objects;

/**
 * An array of objects that are fast to read but a bit slower to add and
 * remove.
 *
 * <p>It is thread-safe.
 *
 * <p>Typical use:
 * <pre>{@code Object[] ary = fra.toArray();
 *for (int j = 0; j < ary.length; ++j)
 *  <i>whatever</i>;}</pre>
 *
 * @author tomyeh
 * @since 3.0.6
 */
public class FastReadArray<T> implements java.io.Serializable, Cloneable {
    private Object[] _ary;

    /** Constructs an array of the specified class.
     */
    public FastReadArray(Class<?> klass) {
        _ary = (Object[])Array.newInstance(klass, 0);
    }
    /** Returns the array (never null).
     * To read, you shall store the return value in a local variable
     * and then iterate thru it.
     *
     * <p>Note: the return array is readonly. Don't modify the value
     * of any element.
     */
    @SuppressWarnings("unchecked")
    public T[] toArray() {
        return (T[])_ary;
    }
    /** Returns if it is empty.
     */
    public boolean isEmpty() {
        return _ary.length == 0;
    }
    /** Returns the size.
     */
    public int size() {
        return _ary.length;
    }
    /** Removes all of the elements for this array.
     * @since 6.0.0
     */
    public void clear() {
        _ary = (Object[])Array.newInstance(_ary.getClass().getComponentType(), 0);
    }

    /** Adds an object.
     */
    synchronized public void add(T val) {
        Object[] ary = (Object[])ArraysX.resize(_ary, _ary.length + 1);
        ary[_ary.length] = val;
        _ary = ary;
    }
    /** Removes an object.
     * @return whether the object is removed successfully (i.e., found).
     */
    @SuppressWarnings("unchecked")
    synchronized public boolean remove(T val) {
        final List l = new LinkedList();
        boolean found = false;
        for (int j = 0; j < _ary.length; ++j)
            if (found || !Objects.equals(val, _ary[j]))
                l.add(_ary[j]);
            else
                found = true;

        if (found)
            _ary = (Object[])l.toArray((Object[])
                Array.newInstance(_ary.getClass().getComponentType(), l.size()));
        return found;
    }
    /** Removes the object(s) that matches the specified condition.
     * By match we mean {@link Comparable#compareTo} returns 0.
     * In other words, this method invokes val.compareTo() against
     * each element in this array.
     *
     * @param atMostOne whether to remove the first matched object only.
     * If true, only the first matched object, if any, is removed.
     * If false, all matched object are removed.
     */
    @SuppressWarnings("unchecked")
    synchronized public boolean removeBy(Comparable val, boolean atMostOne) {
        final List l = new LinkedList();
        boolean found = false;
        for (int j = 0; j < _ary.length; ++j)
            if ((atMostOne && found) || val.compareTo(_ary[j]) != 0)
                l.add(_ary[j]);
            else
                found = true;

        if (found)
            _ary = (Object[])l.toArray((Object[])
                Array.newInstance(_ary.getClass().getComponentType(), l.size()));
        return found;
    }

    public Object clone() {
        //No need to deep copy _ary since it is considered as readonly
        try {
            return super.clone();
        }catch(CloneNotSupportedException e) {
            throw new InternalError();
        }
    }

    //Object//
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (!(o instanceof FastReadArray))
            return false;

        return Objects.equals(_ary, ((FastReadArray)o)._ary);
    }
    public int hashCode() {
        return Objects.hashCode(_ary);
    }
    public String toString() {
        return Objects.toString(_ary);
    }
}