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

org.eclipse.sisu.inject.MildElements Maven / Gradle / Ivy

There is a newer version: 3.0.0-alpha-3
Show newest version
/*
 * Copyright (c) 2010-2024 Sonatype, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *   Stuart McCulloch (Sonatype, Inc.) - initial API and implementation
 */
package org.eclipse.sisu.inject;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

/**
 * NON-thread-safe {@link Collection} of elements kept alive by soft/weak {@link Reference}s.
 */
final class MildElements
    extends AbstractCollection
{
    // ----------------------------------------------------------------------
    // Implementation fields
    // ----------------------------------------------------------------------

    private final ReferenceQueue queue = new ReferenceQueue();

    final List> list;

    private final boolean soft;

    // ----------------------------------------------------------------------
    // Constructors
    // ----------------------------------------------------------------------

    MildElements( final List> list, final boolean soft )
    {
        this.list = list;
        this.soft = soft;
    }

    // ----------------------------------------------------------------------
    // Public methods
    // ----------------------------------------------------------------------

    @Override
    public boolean add( final T element )
    {
        compact();

        return list.add( soft ? new Soft( element, queue, list.size() )
                              : new Weak( element, queue, list.size() ) );
    }

    @Override
    public int size()
    {
        compact();

        return list.size();
    }

    @Override
    public Iterator iterator()
    {
        compact();

        return new Itr();
    }

    // ----------------------------------------------------------------------
    // Implementation methods
    // ----------------------------------------------------------------------

    /**
     * Compacts the list by replacing unreachable {@link Reference}s with ones from the end.
     */
    private void compact()
    {
        for ( Reference ref; ( ref = queue.poll() ) != null; )
        {
            evict( ref );
        }
    }

    /**
     * Evicts a single {@link Reference} from the list; replacing it with one from the end.
     * 
     * @param ref The reference to evict
     */
    void evict( final Reference ref )
    {
        final int index = ( (Indexable) ref ).index( -1 );
        if ( index >= 0 )
        {
            final Reference last = list.remove( list.size() - 1 );
            if ( ref != last )
            {
                ( (Indexable) last ).index( index );
                list.set( index, last );
            }
        }
    }

    // ----------------------------------------------------------------------
    // Implementation types
    // ----------------------------------------------------------------------

    /**
     * Represents an element that can be indexed.
     */
    private interface Indexable
    {
        int index( int index );
    }

    /**
     * {@link Iterator} that iterates over reachable {@link Reference}s in the list.
     */
    final class Itr
        implements Iterator
    {
        // ----------------------------------------------------------------------
        // Implementation fields
        // ----------------------------------------------------------------------

        private int index;

        private T nextElement;

        private boolean haveElement;

        // ----------------------------------------------------------------------
        // Public methods
        // ----------------------------------------------------------------------

        public boolean hasNext()
        {
            // find next element that is still reachable
            while ( null == nextElement && index < list.size() )
            {
                nextElement = list.get( index++ ).get();
            }
            return null != nextElement;
        }

        public T next()
        {
            haveElement = hasNext();
            if ( haveElement )
            {
                // populated by hasNext()
                final T element = nextElement;
                nextElement = null;
                return element;
            }
            throw new NoSuchElementException();
        }

        public void remove()
        {
            if ( haveElement )
            {
                evict( list.get( --index ) );
                haveElement = false;
            }
            else
            {
                throw new IllegalStateException();
            }
        }
    }

    /**
     * Soft {@link Indexable} element.
     */
    private static final class Soft
        extends SoftReference
        implements Indexable
    {
        // ----------------------------------------------------------------------
        // Implementation fields
        // ----------------------------------------------------------------------

        private int index;

        // ----------------------------------------------------------------------
        // Constructors
        // ----------------------------------------------------------------------

        Soft( final T value, final ReferenceQueue queue, final int index )
        {
            super( value, queue );
            this.index = index;
        }

        // ----------------------------------------------------------------------
        // Public methods
        // ----------------------------------------------------------------------

        public int index( final int newIndex )
        {
            final int oldIndex = index;
            index = newIndex;
            return oldIndex;
        }
    }

    /**
     * Weak {@link Indexable} element.
     */
    private static final class Weak
        extends WeakReference
        implements Indexable
    {
        // ----------------------------------------------------------------------
        // Implementation fields
        // ----------------------------------------------------------------------

        private int index;

        // ----------------------------------------------------------------------
        // Constructors
        // ----------------------------------------------------------------------

        Weak( final T value, final ReferenceQueue queue, final int index )
        {
            super( value, queue );
            this.index = index;
        }

        // ----------------------------------------------------------------------
        // Public methods
        // ----------------------------------------------------------------------

        public int index( final int newIndex )
        {
            final int oldIndex = index;
            index = newIndex;
            return oldIndex;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy