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

org.eclipse.sisu.inject.RankedSequence 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.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
 * Ordered {@link List} that arranges elements by descending rank; supports concurrent iteration and modification.
 */
final class RankedSequence
    implements Iterable
{
    // ----------------------------------------------------------------------
    // Constants
    // ----------------------------------------------------------------------

    private static final long serialVersionUID = 1L;

    @SuppressWarnings( "rawtypes" )
    private static final AtomicReferenceFieldUpdater CONTENT_UPDATER =
        AtomicReferenceFieldUpdater.newUpdater( RankedSequence.class, Content.class, "content" );

    // ----------------------------------------------------------------------
    // Implementation fields
    // ----------------------------------------------------------------------

    volatile Content content; // NOSONAR

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

    RankedSequence()
    {
        // nothing to do
    }

    RankedSequence( final RankedSequence sequence )
    {
        if ( null != sequence )
        {
            content = sequence.content;
        }
    }

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

    /**
     * Inserts the given element into the ordered list, using the assigned rank as a guide.
     * 

* The rank can be any value from {@link Integer#MIN_VALUE} to {@link Integer#MAX_VALUE}. * * @param element The element to insert * @param rank The assigned rank */ public void insert( final T element, final int rank ) { Content o, n; do { n = null != ( o = content ) ? o.insert( element, rank ) : new Content( element, rank ); } while ( !CONTENT_UPDATER.compareAndSet( this, o, n ) ); } @SuppressWarnings( "unchecked" ) public T peek() { final Content snapshot = content; return null != snapshot ? (T) snapshot.objs[0] : null; } public boolean contains( final Object element ) { final Content snapshot = content; return null != snapshot && snapshot.indexOf( element ) >= 0; } public boolean containsThis( final Object element ) { final Content snapshot = content; return null != snapshot && snapshot.indexOfThis( element ) >= 0; } @SuppressWarnings( "unchecked" ) public T remove( final Object element ) { Content o, n; int index; do { if ( null == ( o = content ) || ( index = o.indexOf( element ) ) < 0 ) { return null; } n = o.remove( index ); } while ( !CONTENT_UPDATER.compareAndSet( this, o, n ) ); return (T) o.objs[index]; } public boolean removeThis( final T element ) { Content o, n; do { final int index; if ( null == ( o = content ) || ( index = o.indexOfThis( element ) ) < 0 ) { return false; } n = o.remove( index ); } while ( !CONTENT_UPDATER.compareAndSet( this, o, n ) ); return true; } @SuppressWarnings( { "rawtypes", "unchecked" } ) public Iterable snapshot() { final Content snapshot = content; return null != snapshot ? (List) Arrays.asList( snapshot.objs ) : Collections.EMPTY_SET; } public void clear() { content = null; } public boolean isEmpty() { return null == content; } public int size() { final Content snapshot = content; return null != snapshot ? snapshot.objs.length : 0; } public Itr iterator() { return new Itr(); } // ---------------------------------------------------------------------- // Implementation methods // ---------------------------------------------------------------------- /** * Turns the given (potentially non-unique) rank into a unique id by appending a counter. * * @param rank The assigned rank * @param uniq The unique counter * @return The unique id */ static long rank2uid( final int rank, final int uniq ) { return (long) ~rank << 32 | 0x00000000FFFFFFFFL & uniq; } /** * Extracts the original (potentially non-unique) assigned rank from the given unique id. * * @param uid The unique id * @return Assigned rank */ static int uid2rank( final long uid ) { return (int) ( ~uid >>> 32 ); } /** * Finds the insertion point with the nearest UID, regardless of whether the UID is in the list or not. *

* Unlike {@link Arrays#binarySearch} this will always return a number from zero to {@link #size()} inclusive. * * @param uids The UIDs array * @param uid The UID to find * @return Index with nearest UID */ static int safeBinarySearch( final long[] uids, final long uid ) { if ( uid < uids[0] ) { return 0; } int min = 0; int max = uids.length - 1; while ( min < max ) { final int m = min + max >>> 1; if ( uid <= uids[m] ) { max = m; } else { min = m + 1; } } if ( min == uids.length - 1 && uids[min] < uid ) { min++; // append } return min; } // ---------------------------------------------------------------------- // Implementation types // ---------------------------------------------------------------------- /** * Represents an immutable snapshot of ranked elements. */ static final class Content { // ---------------------------------------------------------------------- // Implementation fields // ---------------------------------------------------------------------- final Object[] objs; final long[] uids; final int uniq; // ---------------------------------------------------------------------- // Constructors // ---------------------------------------------------------------------- Content( final Object element, final int rank ) { objs = new Object[] { element }; uids = new long[] { rank2uid( rank, 0 ) }; uniq = 1; } Content( final Object[] objs, final long[] uids, final int uniq ) // NOPMD { this.objs = objs; this.uids = uids; this.uniq = uniq; } // ---------------------------------------------------------------------- // Public methods // ---------------------------------------------------------------------- public int indexOf( final Object element ) { if ( null == element ) { return indexOfThis( null ); } for ( int i = 0; i < objs.length; i++ ) { if ( element.equals( objs[i] ) ) { return i; } } return -1; } public int indexOfThis( final Object element ) { for ( int i = 0; i < objs.length; i++ ) { if ( element == objs[i] ) { return i; } } return -1; } public Content insert( final Object element, final int rank ) { final int size = objs.length + 1; final Object[] newObjs = new Object[size]; final long[] newUIDs = new long[size]; final long uid = rank2uid( rank, uniq ); final int index = safeBinarySearch( uids, uid ); if ( index > 0 ) { System.arraycopy( objs, 0, newObjs, 0, index ); System.arraycopy( uids, 0, newUIDs, 0, index ); } newObjs[index] = element; newUIDs[index] = uid; final int destPos = index + 1, len = size - destPos; if ( len > 0 ) { System.arraycopy( objs, index, newObjs, destPos, len ); System.arraycopy( uids, index, newUIDs, destPos, len ); } return new Content( newObjs, newUIDs, uniq + 1 ); } public Content remove( final int index ) { if ( objs.length == 1 ) { return null; } final int size = objs.length - 1; final Object[] newObjs = new Object[size]; final long[] newUIDs = new long[size]; if ( index > 0 ) { System.arraycopy( objs, 0, newObjs, 0, index ); System.arraycopy( uids, 0, newUIDs, 0, index ); } final int srcPos = index + 1, len = size - index; if ( len > 0 ) { System.arraycopy( objs, srcPos, newObjs, index, len ); System.arraycopy( uids, srcPos, newUIDs, index, len ); } return new Content( newObjs, newUIDs, uniq ); } } /** * Custom {@link Iterator} that copes with modification by repositioning itself in the updated list. */ final class Itr implements Iterator { // ---------------------------------------------------------------------- // Implementation fields // ---------------------------------------------------------------------- private Content snapshot; private T nextObj; private long nextUID = Long.MIN_VALUE; private int index = -1; // ---------------------------------------------------------------------- // Public methods // ---------------------------------------------------------------------- @SuppressWarnings( "unchecked" ) public boolean hasNext() { if ( null != nextObj ) { return true; } final Content newSnapshot = content; if ( snapshot != newSnapshot ) { index = null != newSnapshot ? safeBinarySearch( newSnapshot.uids, nextUID ) : -1; snapshot = newSnapshot; } if ( index >= 0 && index < snapshot.objs.length ) // NOSONAR { nextObj = (T) snapshot.objs[index]; nextUID = snapshot.uids[index]; return true; } return false; } /** * @return {@code true} if the next element is ranked at or above the given rank; otherwise {@code false} */ public boolean hasNext( final int rank ) { if ( null != nextObj ) { return uid2rank( nextUID ) >= rank; } final Content newSnapshot = content; if ( snapshot != newSnapshot ) { index = null != newSnapshot ? safeBinarySearch( newSnapshot.uids, nextUID ) : -1; snapshot = newSnapshot; } if ( index >= 0 && index < snapshot.uids.length ) // NOSONAR { return uid2rank( snapshot.uids[index] ) >= rank; } return false; } public T next() { if ( hasNext() ) { nextUID++; // guarantees progress when re-positioning index++; // populated by hasNext() final T element = nextObj; nextObj = null; return element; } throw new NoSuchElementException(); } public int rank() { return uid2rank( nextUID ); } public void remove() { throw new UnsupportedOperationException(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy