All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.agroal.pool.util.StampedCopyOnWriteArrayList Maven / Gradle / Ivy

There is a newer version: 2.5
Show newest version
// Copyright (C) 2017 Red Hat, Inc. and individual contributors as indicated by the @author tags.
// You may not use this file except in compliance with the Apache License, Version 2.0.

package io.agroal.pool.util;

import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Spliterator;
import java.util.concurrent.locks.StampedLock;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;

import static java.lang.System.arraycopy;
import static java.lang.reflect.Array.newInstance;

/**
 * @author Luis Barreiro
 */
public final class StampedCopyOnWriteArrayList implements List {

    private final Iterator emptyIterator = new Iterator() {
        @Override
        public boolean hasNext() {
            return false;
        }

        @Override
        public T next() {
            throw new NoSuchElementException();
        }
    };
    
    private final StampedLock lock;
    private long optimisticStamp;
    private T[] data;

    // -- //

    @SuppressWarnings( "unchecked" )
    public StampedCopyOnWriteArrayList(Class clazz) {
        this.data = (T[]) newInstance( clazz, 0 );
        lock = new StampedLock();
        optimisticStamp = lock.tryOptimisticRead();
    }

    public T[] getUnderlyingArray() {
        T[] array = data;
        if ( lock.validate( optimisticStamp ) ) {
            return array;
        }

        // Acquiring a read lock does not increment the optimistic stamp
        long stamp = lock.readLock();
        try {
            return data;
        } finally {
            lock.unlockRead( stamp );
        }
    }

    @Override
    public T get(int index) {
        return getUnderlyingArray()[index];
    }

    @Override
    public int size() {
        return getUnderlyingArray().length;
    }

    // --- //

    @Override
    public boolean isEmpty() {
        return size() == 0;
    }

    @Override
    public T set(int index, T element) {
        long stamp = lock.writeLock();
        try {
            T old = data[index];
            data[index] = element;
            return old;
        } finally {
            optimisticStamp = lock.tryConvertToOptimisticRead( stamp );
        }
    }

    @Override
    public boolean add(T element) {
        long stamp = lock.writeLock();
        try {
            data = Arrays.copyOf( data, data.length + 1 );
            data[data.length - 1] = element;
            return true;
        } finally {
            optimisticStamp = lock.tryConvertToOptimisticRead( stamp );
        }
    }

    public T removeLast() {
        long stamp = lock.writeLock();
        try {
            T element = data[data.length - 1];
            data = Arrays.copyOf( data, data.length - 1 );
            return element;
        } finally {
            optimisticStamp = lock.tryConvertToOptimisticRead( stamp );
        }
    }

    @Override
    public boolean remove(Object element) {
        long stamp = lock.readLock();
        try {
            boolean found = true;

            while ( found ) {
                T[] array = data;
                found = false;

                for ( int index = array.length - 1; index >= 0; index-- ) {
                    if ( element == array[index] ) {
                        found = true;

                        long writeStamp = lock.tryConvertToWriteLock( stamp );
                        if ( writeStamp != 0 ) {
                            stamp = writeStamp;

                            T[] newData = Arrays.copyOf( data, data.length - 1 );
                            arraycopy( data, index + 1, newData, index, data.length - index - 1 );
                            data = newData;
                            return true;
                        } else {
                            break;
                        }
                    }
                }
            }
            return false;
        } finally {
            optimisticStamp = lock.tryConvertToOptimisticRead( stamp );
        }
    }

    @Override
    public T remove(int index) {
        long stamp = lock.writeLock();
        try {
            T old = data[index];
            T[] array = Arrays.copyOf( data, data.length - 1 );
            if ( data.length - index - 1 != 0 ) {
                arraycopy( data, index + 1, array, index, data.length - index - 1 );
            }
            data = array;
            return old;
        } finally {
            optimisticStamp = lock.tryConvertToOptimisticRead( stamp );
        }
    }

    @Override
    public void clear() {
        long stamp = lock.writeLock();
        try {
            data = Arrays.copyOf( data, 0 );
        } finally {
            optimisticStamp = lock.tryConvertToOptimisticRead( stamp );
        }
    }

    @Override
    public boolean contains(Object o) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Iterator iterator() {
        T[] array = getUnderlyingArray();
        return array.length == 0 ? emptyIterator : new UncheckedIterator<>( array );
    }

    @Override
    public boolean addAll(Collection c) {
        long stamp = lock.writeLock();
        try {
            int oldSize = data.length;
            data = Arrays.copyOf( data, oldSize + c.size() );
            for ( T element : c ) {
                data[oldSize++] = element;
            }
            return true;
        } finally {
            optimisticStamp = lock.tryConvertToOptimisticRead( stamp );
        }
    }

    // --- //

    @Override
    public Object[] toArray() {
        throw new UnsupportedOperationException();
    }

    @Override
    public  E[] toArray(E[] a) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean containsAll(Collection c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean addAll(int index, Collection c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean removeAll(Collection c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean retainAll(Collection c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void add(int index, T element) {
        throw new UnsupportedOperationException();
    }

    @Override
    public int indexOf(Object o) {
        throw new UnsupportedOperationException();
    }

    @Override
    public int lastIndexOf(Object o) {
        throw new UnsupportedOperationException();
    }

    @Override
    public ListIterator listIterator() {
        throw new UnsupportedOperationException();
    }

    @Override
    public ListIterator listIterator(int index) {
        throw new UnsupportedOperationException();
    }

    @Override
    public List subList(int fromIndex, int toIndex) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Stream stream() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Stream parallelStream() {
        throw new UnsupportedOperationException();
    }

    @Override
    public void forEach(Consumer action) {
        for ( T element : this ) {
            action.accept( element );
        }
    }

    @Override
    public Spliterator spliterator() {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean removeIf(Predicate filter) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void replaceAll(UnaryOperator operator) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void sort(Comparator c) {
        throw new UnsupportedOperationException();
    }

    // --- //

    private static final class UncheckedIterator implements Iterator {

        private final int size;

        private final T[] data;

        private int index = 0;

        public UncheckedIterator(T[] data) {
            this.data = data;
            this.size = data.length;
        }

        @Override
        public boolean hasNext() {
            return index < size;
        }

        @Override
        public T next() {
            if ( index < size ) {
                return data[index++];
            }
            throw new NoSuchElementException( "No more elements in this list" );
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy