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

com.tangosol.util.AbstractSafeLongArray Maven / Gradle / Ivy

There is a newer version: 24.03
Show newest version
/*
 * Copyright (c) 2000, 2020, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */

package com.tangosol.util;


import com.oracle.coherence.common.util.AutoLock.Sentry;


/**
 * An abstract base class for thread-safe {@link LongArray}s which are protected by lock(s).
 *
 * @author mf 2014.10.01
 */
public abstract class AbstractSafeLongArray
        implements LongArray
    {
    @Override
    public V get(long lIndex)
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().get(lIndex);
            }
        }

    @Override
    public long floorIndex(long lIndex)
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().floorIndex(lIndex);
            }
        }

    @Override
    public V floor(long lIndex)
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().floor(lIndex);
            }
        }

    @Override
    public long ceilingIndex(long lIndex)
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().ceilingIndex(lIndex);
            }
        }

    @Override
    public V ceiling(long lIndex)
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().ceiling(lIndex);
            }
        }

    @Override
    public V set(long lIndex, V oValue)
        {
        try (Sentry> sentry = acquireWriteLock())
            {
            return sentry.getResource().set(lIndex, oValue);
            }
        }

    @Override
    public long add(V oValue)
        {
        try (Sentry> sentry = acquireWriteLock())
            {
            return sentry.getResource().add(oValue);
            }
        }

    @Override
    public boolean exists(long lIndex)
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().exists(lIndex);
            }
        }

    @Override
    public V remove(long lIndex)
        {
        try (Sentry> sentry = acquireWriteLock())
            {
            return sentry.getResource().remove(lIndex);
            }
        }

    @Override
    public void remove(long lIndexFrom, long lIndexTo)
        {
        try (Sentry> sentry = acquireWriteLock())
            {
            sentry.getResource().remove(lIndexFrom, lIndexTo);
            }
        }

    @Override
    public boolean contains(V oValue)
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().contains(oValue);
            }
        }

    @Override
    public void clear()
        {
        try (Sentry> sentry = acquireWriteLock())
            {
            sentry.getResource().clear();
            }
        }

    @Override
    public boolean isEmpty()
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().isEmpty();
            }
        }

    @Override
    public int getSize()
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().getSize();
            }
        }

    @Override
    public long getFirstIndex()
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().getFirstIndex();
            }
        }

    @Override
    public long getLastIndex()
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().getLastIndex();
            }
        }

    @Override
    public long indexOf(V oValue)
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().indexOf(oValue);
            }
        }

    @Override
    public long indexOf(V oValue, long lIndex)
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().indexOf(oValue, lIndex);
            }
        }

    @Override
    public long lastIndexOf(V oValue)
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().lastIndexOf(oValue);
            }
        }

    @Override
    public long lastIndexOf(V oValue, long lIndex)
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().lastIndexOf(oValue, lIndex);
            }
        }

    @Override
    public Iterator iterator()
        {
        return instantiateSafeIterator(/*fForward*/ true, Long.MIN_VALUE);
        }

    @Override
    public Iterator iterator(long lIndex)
        {
        return instantiateSafeIterator(/*fForward*/ true, lIndex);
        }

    @Override
    public Iterator reverseIterator()
        {
        return instantiateSafeIterator(/*fForward*/ false, Long.MAX_VALUE);
        }

    @Override
    public Iterator reverseIterator(long lIndex)
        {
        return instantiateSafeIterator(/*fForward*/ false, lIndex);
        }


    // ----- Object interface -----------------------------------------------

    @Override
    public String toString()
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return sentry.getResource().toString();
            }
        }

    @Override
    abstract public AbstractSafeLongArray clone();



    // ----- AbstractSafeLongArray ------------------------------------------

    /**
     * Acquire the read lock.
     *
     * @return the lock sentry
     */
    protected abstract Sentry> acquireReadLock();

    /**
     * Acquire the write lock.
     *
     * @return the lock sentry
     */
    protected abstract Sentry> acquireWriteLock();


    // ----- inner class: SafeIterator -------------------------------------

    /**
     * Instantiate a SafeIterator around the specified delegate iterator.
     *
     * @param fForward    true if a forward iterator is to be returned
     * @param lIndexFrom  the start index
     *
     * @return the safe iterator
     */
    protected SafeIterator instantiateSafeIterator(boolean fForward, long lIndexFrom)
        {
        try (Sentry> sentry = acquireReadLock())
            {
            return new SafeIterator(sentry.getResource(), fForward, lIndexFrom);
            }
        }

    /**
     * A lock based LongArray Iterator.  Note the implementation is thread-safe so long as
     * the wrapped unsafe LongArray supports stable iteration when accessed from a single thread.
     * Specifically that performing an add or remove operation directly against the LongArray
     * while being iterated does not corrupt the state of either the LongArray or the Iterator.
     *
     * An alternate approach would be to maintain a write counter and to refresh the delegate iterator
     * each time the write counter changes, the refresh would be cheap as it could use iterator(m_lastIndex).
     */
    protected class SafeIterator
            implements Iterator
        {
        protected SafeIterator(LongArray delegate, boolean fForward, long lIndexFrom)
            {
            f_delegate = fForward
                 ? lIndexFrom == Long.MIN_VALUE
                     ? delegate.iterator()
                     : delegate.iterator(lIndexFrom)
                 : lIndexFrom == Long.MAX_VALUE
                     ? delegate.reverseIterator()
                     : delegate.reverseIterator(lIndexFrom);
            }

        @Override
        public boolean hasNext()
            {
            try (Sentry sentry = acquireReadLock())
                {
                return f_delegate.hasNext();
                }
            }

        @Override
        public V next()
            {
            V    value;
            long lIndex;
            try (Sentry sentry = acquireReadLock())
                {
                value  = f_delegate.next();
                lIndex = f_delegate.getIndex();
                }

            m_valueLast  = value;
            m_lIndexLast = lIndex;

            return value;
            }

        @Override
        public long getIndex()
            {
            // no need to take lock, use cached index
            ensureValid();
            return m_lIndexLast;
            }

        @Override
        public V getValue()
            {
            // no need to take lock, use cached value
            ensureValid();
            return (V) m_valueLast;
            }

        @Override
        public V setValue(V oValue)
            {
            try (Sentry sentry = acquireWriteLock())
                {
                V value = f_delegate.setValue(oValue);
                m_valueLast = oValue;
                return value;
                }
            }

        @Override
        public void remove()
            {
            try (Sentry sentry = acquireWriteLock())
                {
                f_delegate.remove();
                }
            m_valueLast = NO_VALUE;
            }

        /**
         * Ensure that the cached value/index are valid.
         */
        protected void ensureValid()
            {
            if (m_valueLast == NO_VALUE)
                {
                throw new IllegalStateException("missing call to next()");
                }
            }

        /**
         * The delegate iterator.
         */
        protected final Iterator f_delegate;

        /**
         * The last value returned from the iterator.
         */
        protected Object m_valueLast = NO_VALUE;

        /**
         * The index associated with the last returned value
         */
        protected long m_lIndexLast;
        }

    /**
     * A value guaranteed to never be in the array.
     */
    protected static final Object NO_VALUE = new Object();
    }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy