Package org.squarebrackets

Source Code of org.squarebrackets.BoundedCharBufferArrayImpl$SubBoundedCharBufferArrayImpl

/*
* ============================================================================
* GNU Lesser General Public License
* ============================================================================
*
* Square Brackets - Java Array Framework.
* Copyright (C) 2013  Beatgrid Media B.V.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
*
* Beatgrid Media B.V.
* Sisalbaan 5-A
* 2352 AZ Leiderdorp
* The Netherlands
*
* info@squarebrackets.org
* http://squarebrackets.org
*/
package org.squarebrackets;

import org.squarebrackets.function.CharConsumer;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.NotThreadSafe;
import java.io.File;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Path;
import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;

import static java.util.Objects.requireNonNull;

/**
* <p>Bounded-size mutable wrapper for {@code CharBuffer}s.</p>
*
* <p>This bounded char array is constructed by the static interface method of {@code BoundedCharArray}. The
* {@code valueOf} method wraps a new {@code BoundedCharArray} around a char buffer.</p>
*
* <p>Arrays express characteristics to indicate that, for instance, elements are listed in sorted order, or no
* duplicate elements exist. These characteristics allow array implementations to optimize their algorithms based
* on the contents of the array. For example, operations that lookup elements can use a binary search algorithm if
* the array is marked as being sorted. These optimizations may reduce the time complexity of such operations by
* several orders of magnitude.
* Bounded primitive arrays, such as this class, always report {@code RESIZABLE}, {@code MUTABLE} and {@code NONNULL}.</p>
*
* <p>This class attempts to establish these characteristics to accommodate these optimizations at best effort. This
* means that this implementation determines which set of characteristics apply to its elements without traversing these
* elements, in other words, without incurring a performance penalty. Characteristics are always invalidated if
* conditions of these characteristics are broken as result of array modification. Characteristics are only added in
* scenarios in which their conditions can be 'tested' without traversal of elements. For example, the {@code SORTED}
* characteristic is added if the length of an array is reduced to zero or one element, or if all elements are replaced
* by an array that is marked as being sorted. The semantics of characteristics processing is documented for each
* "destructive" method. Users can take full control of characteristics assignment by means of the
* {@link org.squarebrackets.MutableArray#doAction(org.squarebrackets.ArrayAction)} method.</p>
*
* @author Leon van Zantvoort
*/
@NotThreadSafe
class BoundedCharBufferArrayImpl extends MutableCharBufferArrayImpl implements BoundedCharArray {

    /** Specifies if reserved elements need to be reset to default values. */
    private boolean clearReservedElements = false;

    /** Counter for fail-fast error detection. */
    protected transient int modCount = 0;

    /** Memory mapped file, or {@code null} if array is not backed by a memory mapped file. */
    private final File file;

    /** Memory mapped buffer, or {@code null} if array is not backed by a memory mapped file. */
    private final transient MappedByteBuffer buffer;

    /**
     * Package visible constructor.
     *
     * @param buffer backing buffer.
     * @param characteristics array characteristics.
     * @param duplicate {@code true} to duplicate the {@code buffer}, {@code false} to use {@code buffer} reference
     *                  as backing buffer.
     * @throws IllegalArgumentException if buffer is read only.
     */
    BoundedCharBufferArrayImpl(@Nonnull CharBuffer buffer, int characteristics, boolean duplicate) {
        super(buffer, characteristics, duplicate);
        this.file = null;
        this.buffer = null;
    }

    /**
     * Package visible constructor.
     */
    BoundedCharBufferArrayImpl(@Nonnull Path file, int capacity) {
        this(file.toFile(), createMappedBuffer(file.toFile(), capacity, true), 0);
    }

    /**
     * Private constructor.
     */
    private BoundedCharBufferArrayImpl(@Nonnull File file, @Nonnull MappedByteBuffer buffer, int length) {
        super((CharBuffer) buffer.asCharBuffer().limit(length), 0, false);
        this.file = file;
        this.buffer = buffer;
    }

    /**
     * Allow array implementation to filter characteristics based on array specific logic.
     *
     * <p>Default implementation passes specified value straight through.</p>
     *
     * @param characteristics characteristics to be filtered.
     * @return the filtered characteristics.
     */
    @Override
    protected int filterCharacteristics(int characteristics) {
        return (characteristics | NONNULL | MUTABLE | RESIZABLE) & ~REPLACEABLE;
    }

    /**
     * Specifies if reserved elements need to be reset to default values. This flag is set to {@code false} by default
     * for primitive arrays.
     *
     * @param flag {@code true} if reserved elements need to be reset, {@code false} otherwise.
     */
    @Override
    public void setClearReservedElements(boolean flag) {
        // Must not be invoked as sub array.
        clearReservedElements = flag;
    }

    /**
     * Returns {@code true} if reserved elements need to be reset to default values, {@code false} otherwise.
     *
     * <p>Sub arrays must override this method and delegate the invocation to the parent.</p>
     *
     * @return {@code true} if reserved elements need to be reset, {@code false} otherwise.
     */
    protected boolean clearReservedElements() {
        return clearReservedElements;
    }

    /**
     * Fail-fast error detection. Sub classes (such as sub arrays) may override this method if they wish to implement
     * concurrent modification checking.
     *
     * @throws ConcurrentModificationException if parent array has been structurally modified.
     */
    protected void checkForComodification() {
    }

    /**
     * Updates length of this array and increases modCount.
     *
     * <p>Sub arrays must override this method and delegate the invocation this implementation by calling
     * {@code super.updateLength()}, next they must delegate the invocation to the parent array.</p>
     *
     * @param diff number of elements that are added / removed.
     */
    protected void updateLength(int diff) {
        modCount++; // Sub arrays must increment modCount of parent array as well.
        int newLimit = elements.limit() + diff;
        if (clearReservedElements && diff < 0) {
            elements.mark().position(newLimit);
            while (elements.hasRemaining()) {
                elements.put((char) 0);
            }
            elements.reset();
        }
        elements.limit(newLimit);
    }

    /**
     * Returns the number of additional elements that this array can store (in the absence of memory or resource
     * constraints), or {@code Integer.MAX_VALUE} if there is no intrinsic limit.
     *
     * @return the remaining capacity.
     */
    @Override
    public int remainingCapacity() {
        return elements.capacity() - elements.limit();
    }

    /**
     * Iterates through the array and invokes the consumer's {@code accept} method for each value within this array.
     *
     * @param consumer consumer that is called for each value within this array.
     * @throws NullPointerException if the specified consumer is null.
     */
    @SuppressWarnings("ConstantConditions")
    @Override
    public void forEachChar(@Nonnull CharConsumer consumer) {
        requireNonNull(consumer);
        final int expectedModCount = modCount;
        if (elements.hasArray()) {
            final char[] a = elements.array();
            final int fromIndex = offset();
            final int toIndex = fromIndex + elements.limit();
            for (int index = fromIndex; modCount == expectedModCount && index < toIndex; index++) {
                consumer.accept(a[index]);
            }
        } else {
            final int fromIndex = elements.position();
            final int toIndex = elements.limit();
            for (int index = fromIndex; modCount == expectedModCount && index < toIndex; index++) {
                consumer.accept(elements.get(index));
            }
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

    /**
     * Replaces all elements of this array by the elements of the specified array. The semantics of this method are less
     * strict than the ones expressed by {@code MutableArray}; The length of the array that is passed as argument needs
     * to be less than or equal to this array's capacity.
     *
     * <p>The length of {@code this} array is increased or decreased by length difference between {@code this} array and
     * {@code array} argument.</p>
     *
     * <p><strong>Characteristics:</strong></p>
     *
     * <p>Modification of this array may affect the array's characteristics. The array implementations of the
     * Java Array Framework, as returned by the static factory methods, adhere to the characteristics contract:</p>
     *
     * <ul>
     *   <li>if the specified {@code array} reports {@code SORTED}, {@code SORTED} is reported after this invocation if
     *   the comparator of the specified {@code array} is equal to this array's comparator;</li>
     *   <li>if the specified {@code array} reports {@code SORTED} and {@code DISTINCT}, {@code DISTINCT} is reported
     *   after this invocation if the comparator of the specified {@code array} is equal to this array's comparator.
     * </ul>
     *
     * @param array array to replace elements of this array.
     * @throws NullPointerException if the specified array is null or if the element is replaced with a null value.
     * @throws IllegalStateException if elements cannot be replaced due to capacity issues.
     */
    @SuppressWarnings("InconsistentJavaDoc")
    @Override
    public void setAll(@Nonnull Array<? extends Character> array) {
        int offset = elements.position();
        int arrayLength = array.length();
        if (arrayLength <= elements.capacity() - offset) {
            int length = elements.remaining();
            CharArray cast = ArrayCast.toCharArray(array);
            if (cast != null && elements.hasArray()) {
                cast.toArray(elements.array(), offset, arrayLength);
                updateLength(arrayLength - length);   // Invoke updateLength after addition to provide failure atomicity.
            } else {
                char[] a = NativeArrays.toCharArray(array);
                updateLength(arrayLength - length);   // Invoke updateLength after addition to provide failure atomicity.
                elements.mark();
                elements.put(a, 0, arrayLength).reset();
            }
            characteristics(array.characteristics());   // All elements are replaced by new array; Copy characteristics.
            if (hasCharacteristics(SORTED)) {
                if (array.getComparator() != null) {
                    removeCharacteristics(SORTED | DISTINCT);
                } else {
                    updateCharacteristics(offset, array);
                }
            }
        } else {
            throw new IllegalStateException("Array full.");
        }
    }

    /**
     * Appends the specified object to the end of this array. Length of this array is increased by one.
     *
     * <p><strong>Characteristics:</strong></p>
     *
     * <p>Modification of this array may affect this array's characteristics. The array implementations of the
     * Java Array Framework, as returned by the static factory methods, adhere to the characteristics contract:</p>
     *
     * <ul>
     *   <li>if this array reports {@code SORTED} prior to this call, {@code SORTED} is reported after this
     *   invocation if the specified {@code object} does not break the sorted order of this array;</li>
     *   <li>if this array reports {@code SORTED} and {@code DISTINCT} prior to this call, {@code DISTINCT} is
     *   reported after this invocation if the specified {@code object} was not already present in this array.</li>
     * </ul>
     *
     * @param object object to to be added.
     * @throws NullPointerException if the specified {@code object} is null.
     * @throws IllegalStateException if element cannot be inserted due to capacity issues.
     */
    @SuppressWarnings("InconsistentJavaDoc")
    @Override
    public void add(Character object) {
        if (Tripwire.ENABLED) {
            Tripwire.trip(getClass());
        }
        addChar(object);
    }

    /**
     * Appends the specified char value to the end of this array. Length of this array is increased by one.
     *
     * <p><strong>Characteristics:</strong></p>
     *
     * <p>Modification of this array may affect this array's characteristics. The array implementations of the
     * Java Array Framework, as returned by the static factory methods, adhere to the characteristics contract:</p>
     *
     * <ul>
     *   <li>if this array reports {@code SORTED} prior to this call, {@code SORTED} is reported after this
     *   invocation if the specified {@code object} does not break the sorted order of this array;</li>
     *   <li>if this array reports {@code SORTED} and {@code DISTINCT} prior to this call, {@code DISTINCT} is
     *   reported after this invocation if the specified {@code object} was not already present in this array.</li>
     * </ul>
     *
     * @param value char value to to be added.
     * @throws IllegalStateException if element cannot be inserted due to capacity issues.
     */
    @Override
    public void addChar(char value) {
        int elementIndex = elements.limit();
        if (elementIndex < elements.capacity()) {
            updateLength(1);
            elements.mark().position(elementIndex);
            elements.put(value).reset();
            if (hasCharacteristics(SORTED)) {
                updateCharacteristics(elementIndex, value);
            }
        } else {
            throw new IllegalStateException("Array full.");
        }
    }

    /**
     * Appends the elements of the specified array to the end of this array. Length of {@code this} array is increased
     * by {@code array.length()}.
     *
     * <p><strong>Characteristics:</strong></p>
     *
     * <p>Modification of this array may affect the array's characteristics. The array implementations of the
     * Java Array Framework, as returned by the static factory methods, adhere to the characteristics contract:</p>
     *
     * <ul>
     *   <li>if this array reports {@code SORTED} prior to this call, {@code SORTED} is reported after this
     *   invocation if the specified {@code array} reports {@code SORTED} and if it does not break the sorted order of
     *   this array;</li>
     *   <li>if this array reports {@code SORTED} and {@code DISTINCT} prior to this call, {@code DISTINCT} is reported
     *   after this invocation if the specified {@code array} reports {@code SORTED} and {@code DISTINCT} and if the
     *   specified {@code array} does not contain any objects that were already present in this array.</li>
     * </ul>
     *
     * @param array array to be added.
     * @throws NullPointerException if the specified array is null or if the array contains null elements.
     * @throws IllegalStateException if elements cannot be inserted due to capacity issues.
     */
    @SuppressWarnings("InconsistentJavaDoc")
    @Override
    public void addAll(@Nonnull Array<? extends Character> array) {
        int arrayLength = array.length();
        int elementIndex = elements.limit();
        if (arrayLength <= elements.capacity() - elementIndex) {
            CharArray cast = ArrayCast.toCharArray(array);
            if (cast != null && elements.hasArray()) {
                cast.toArray(elements.array(), elementIndex, arrayLength);
                updateLength(arrayLength)// Invoke updateLength after addition to provide failure atomicity.
            } else {
                char[] a = NativeArrays.toCharArray(array);
                updateLength(arrayLength)// Invoke updateLength after obtaining native array to provide failure atomicity.
                elements.mark().position(elementIndex);
                elements.put(a, 0, arrayLength).reset();
            }
            retainCharacteristics(array.characteristics());
            if (hasCharacteristics(SORTED)) {
                updateCharacteristics(elementIndex, array);
            }
        } else {
            throw new IllegalStateException("Array full.");
        }
    }

    /**
     * Removes last element. Length of this array is decreased by one.
     *
     * <p><strong>Characteristics:</strong></p>
     *
     * <p>Modification of this array may affect the array's characteristics. The array implementations of the
     * Java Array Framework, as returned by the static factory methods, adhere to the characteristics contract:</p>
     *
     * <ul>
     *   <li>if the array contains no elements after this invocation, {@code NONNULL}, {@code SORTED} and
     *   {@code DISTINCT} are reported.
     * </ul>
     *
     * @return element that is removed.
     * @throws NoSuchElementException if array is already empty.
     */
    @Override
    public Character remove() {
        if (Tripwire.ENABLED) {
            Tripwire.trip(getClass());
        }
        return charRemove();
    }

    /**
     * Removes last element. Length of this array is decreased by one.
     *
     * <p><strong>Characteristics:</strong></p>
     *
     * <p>Modification of this array may affect the array's characteristics. The array implementations of the
     * Java Array Framework, as returned by the static factory methods, adhere to the characteristics contract:</p>
     *
     * <ul>
     *   <li>if the array contains one element after this invocation, {@code SORTED} and {@code DISTINCT} are reported.
     * </ul>
     *
     * @return element that is removed.
     * @throws NoSuchElementException if array is already empty.
     */
    @Override
    public char charRemove() {
        int position = elements.position();
        int elementIndex = elements.limit() - 1;
        if (elementIndex >= position) {
            char oldValue = elements.get(elementIndex);
            updateLength(-1);
            if (elements.remaining() <= 1) {
                addCharacteristics(SORTED | DISTINCT);
            }
            return oldValue;
        }
        throw new NoSuchElementException();
    }

    /**
     * Removes all elements.
     *
     * <p><strong>Characteristics:</strong></p>
     *
     * <p>Modification of this array may affect the array's characteristics. The array implementations of the
     * Java Array Framework, as returned by the static factory methods, adhere to the characteristics contract:</p>
     *
     * <ul>
     *   <li>After this invocation, {@code NONNULL}, {@code SORTED} and {@code DISTINCT} are reported.
     * </ul>
     */
    @Override
    public void clear() {
        int length = elements.remaining();
        updateLength(-length);
        addCharacteristics(SORTED | DISTINCT);
    }

    @SuppressWarnings({"MissingMethodJavaDoc", "MissingFieldJavaDoc"})
    private static class SubBoundedCharBufferArrayImpl extends BoundedCharBufferArrayImpl {

        final BoundedCharBufferArrayImpl parent;

        SubBoundedCharBufferArrayImpl(@Nonnull BoundedCharBufferArrayImpl parent, @Nonnull CharBuffer buffer) {
            super(buffer, parent.characteristics, false);
            this.parent = parent;
            this.modCount = parent.modCount;
        }

        @Override
        public void setClearReservedElements(boolean flag) {
            parent.setClearReservedElements(flag)// super.setClearReservedElements() must not be called.
        }

        @Override
        protected boolean clearReservedElements() {
            return parent.clearReservedElements();
        }

        @Override
        protected void checkForComodification() {
            if (modCount != parent.modCount) {
                throw new ConcurrentModificationException();
            }
            parent.checkForComodification();
        }

        @Override
        protected ArrayContext<Character> getArrayContext() {
            return parent.inAction ? null : super.getArrayContext();
        }

        @Override
        protected void updateLength(int diff) {
            super.updateLength(diff);
            parent.updateLength(diff);
        }

        @Override
        protected void updateCharacteristics(int elementIndex, char value) {
            super.updateCharacteristics(elementIndex, value);
            if (hasCharacteristics(SORTED)) {
                parent.updateCharacteristics(elementIndex, value);
            }
        }

        @Override
        protected void updateCharacteristics(int elementIndex, @Nonnull Array<? extends Character> array) {
            super.updateCharacteristics(elementIndex, array);
            if (hasCharacteristics(SORTED)) {
                parent.updateCharacteristics(elementIndex, array);
            }
        }

        @Override
        public int characteristics(int characteristics) {
            // Parent array retains characteristics that are shared with sub array. Additional characteristics
            // assigned to sub array are not set for parent array, as it is not guaranteed that these
            // characteristics hold for parent array.
            parent.retainCharacteristics(characteristics);
            return super.characteristics(characteristics);
        }

        @Override
        public ArrayIterator.OfChar iterator() {
            checkForComodification();
            return super.iterator();
        }

        @Override
        public ArrayIterator.OfChar iterator(int index) {
            checkForComodification();
            return super.iterator(index);
        }

        @Override
        public void forEachChar(@Nonnull CharConsumer consumer) {
            checkForComodification();
            super.forEachChar(consumer);
        }

        @Override
        public char getChar(int index) {
            checkForComodification();
            return super.getChar(index);
        }

        @Override
        public char setChar(int index, char value) {
            checkForComodification();
            return super.setChar(index, value);
        }

        @Override
        public void setAll(@Nonnull Array<? extends Character> array) {
            checkForComodification();
            super.setAll(array);
        }

        @Override
        public void addChar(char value) {
            checkForComodification();
            super.addChar(value);
        }

        @Override
        public void addAll(@Nonnull Array<? extends Character> array) {
            checkForComodification();
            super.addAll(array);
        }

        @Override
        public char charRemove() {
            checkForComodification();
            return super.charRemove();
        }

        @Override
        public void clear() {
            checkForComodification();
            super.clear();
        }

        @Override
        public char[] toArray() {
            checkForComodification();
            return super.toArray();
        }

        @Override
        public char[] toArray(@Nonnull char[] array) {
            checkForComodification();
            return super.toArray(array);
        }

        @Override
        public void toArray(@Nonnull char[] array, int offset, int length) {
            checkForComodification();
            super.toArray(array, offset, length);
        }

        // All default implementations (defender methods) will be checked for concurrent modification either through
        // methods listed above, or through backing buffer access below.

        @Override
        public CharBuffer buffer() {
            checkForComodification();
            return super.buffer();
        }
    }

    /**
     * <p>Returns a new sub array object for the specified {@code offset}. The specified {@code offset} is relative to
     * the existing offset, as returned by {@link #offset()}. The length of the resulting array is reduced by
     * the number of elements that are added to the current offset:</p>
     *
     * <pre>int newLength = length() - offset;</pre>
     *
     * <p>Effectively, the virtual {@code toIndex} of the array remains the same.</p>
     *
     * @param offset new relative offset.
     * @return a new sub array object with the new {@code offset}.
     */
    @Override
    public BoundedCharArray offset(int offset) {
        int newOffset = elements.position() + offset;
        int newLength = elements.remaining() - offset;
        subArrayCheck(newOffset, newLength);
        CharBuffer copy = elements.duplicate();
        copy.position(newOffset);
        return new SubBoundedCharBufferArrayImpl(this, copy);
    }

    /**
     * <p>Returns a new sub array object for the specified {@code length}. Note that {@code length} must be smaller than
     * or equal to the current length, as returned by {@code #length}.</p>
     *
     * @param length new length, must be smaller than or equal to current length.
     * @return a new sub array object with the new {@code length}.
     */
    @Override
    public MutableCharArray length(int length) {
        int offset = elements.position();
        subArrayCheck(offset, length);
        CharBuffer copy = elements.duplicate();
        copy.limit(offset + length);
        return new SubBoundedCharBufferArrayImpl(this, copy);
    }

    /**
     * Convenience method, combining {@code offset(int)} and {@code length(int)}.
     *
     * @param fromIndex low endpoint (inclusive) of the sub array.
     * @param toIndex high endpoint (exclusive) of the sub array.
     * @return a view of the specified range within this array.
     * @throws IndexOutOfBoundsException for an illegal endpoint index value ({@code fromIndex < 0 || toIndex > length ||
     *         fromIndex > toIndex}).
     */
    @Override
    public MutableCharArray subArray(int fromIndex, int toIndex) {
        int offset = elements.position();
        int newOffset = offset + fromIndex;
        int newLength = toIndex - fromIndex;
        subArrayCheck(newOffset, newLength);
        CharBuffer copy = elements.duplicate();
        copy.position(newOffset);
        copy.limit(newOffset + newLength);
        return new SubBoundedCharBufferArrayImpl(this, copy);
    }

    /**
     * Tells whether or not the array's content is resident in physical memory.
     *
     * <p>A return value of {@code true} implies that it is highly likely that all of the data in the array is
     * resident in physical memory and may therefore be accessed without incurring any virtual-memory page
     * faults or I/O operations. A return value of {@code false} does not necessarily imply that the array's content
     * is not resident in physical memory.</p>
     *
     * <p>The returned value is a hint, rather than a guarantee, because the underlying operating system may have paged
     * out some of the array's data by the time that an invocation of this method returns.</p>
     *
     * <p>If this array is not constructed through {@link #newInstance(java.nio.file.Path, int)} then this method always
     * returns {@code true}.</p>
     *
     * @return {@code true} if it is likely that the array's content is resident in physical memory.
     */
    @Override
    public boolean isLoaded() {
        return buffer == null || buffer.isLoaded();
    }

    /**
     * Loads the array's content into physical memory.
     *
     * <p>This method makes a best effort to ensure that, when it returns, the array's content is resident in physical
     * memory. Invoking this method may cause some number of page faults and I/O operations to occur.</p>
     *
     * <p>If this array is not constructed through {@link #newInstance(java.nio.file.Path, int)} then then invoking this
     * method has no effect.</p>
     */
    @Override
    public void load() {
        if (buffer != null) {
            buffer.load();
        }
    }

    /**
     * Forces any changes made to the array's content to be written to the storage device containing the mapped file.
     *
     * <p>If the file mapped into this array resides on a local storage device then when this method returns it is
     * guaranteed that all changes made to the array since it was created, or since this method was last invoked, will
     * have been written to that device.</p>
     *
     * <p>If the file does not reside on a local device then no such guarantee is made.</p>
     *
     * <p>If this array is not constructed through {@link #newInstance(java.nio.file.Path, int)} then then invoking this
     * method has no effect.</p>
     */
    @Override
    public void force() {
        if (buffer != null) {
            buffer.force();
        }
    }

    /**
     * Constructs a mapped byte buffer for the specified capacity.
     *
     * @param file non existing or zero-length file to which memory must be mapped.
     * @param capacity capacity of array.
     * @param newFile true if mapped buffer represents a new file.
     * @return new mapped byte buffer.
     * @throws UncheckedIOException indicates an error with underlying file system, or {@code newFile} is true and
     * file already exists.
     */
    private static MappedByteBuffer createMappedBuffer(@Nonnull File file, int capacity, boolean newFile) {
        try {
            if (newFile && file.exists() && file.length() > 0) {
                throw new FileAlreadyExistsException(file.getPath());
            }
            return new RandomAccessFile(file, "rw").getChannel().
                    map(FileChannel.MapMode.READ_WRITE, 0, Character.SIZE / Byte.SIZE * capacity);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    /**
     * Write replace method for the serialization proxy pattern. This method must be overwritten by sub classes if their
     * serialized form differs from this class.
     *
     * @return serialization proxy.
     */
    @Override
    Object writeReplace() {
        return new SerializationProxy(this);
    }

    @SuppressWarnings("MissingMethodJavaDoc")
    private void readObject(ObjectInputStream s) throws InvalidObjectException {
        throw new InvalidObjectException("Proxy required");
    }

    @SuppressWarnings({"MissingMethodJavaDoc", "MissingFieldJavaDoc"})
    private static class SerializationProxy implements Serializable {
        static final long serialVersionUID = -2929127243624957465L;

        final File file;
        final int length;
        final int capacity;
        final boolean direct;
        final int characteristics;
        final boolean clearReservedElements;
        transient CharBuffer elements;
        transient MappedByteBuffer buffer;

        SerializationProxy(BoundedCharBufferArrayImpl array) {
            this.file = array.file;
            this.length = array.elements.remaining();
            this.capacity = array.elements.capacity() - array.elements.position();
            this.direct = array.elements.isDirect();
            this.characteristics = array.characteristics;
            this.clearReservedElements = array.clearReservedElements();
            this.elements = array.elements;
            this.buffer = array.buffer;
        }

        private void writeObject(ObjectOutputStream s) throws IOException {
            s.defaultWriteObject();
            if (buffer == null) {
                elements.mark();
                for (int i = 0; i < length; i++) {
                    s.writeChar(elements.get());
                }
                elements.reset();
            } else {
                buffer.force();
            }
        }

        private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
            s.defaultReadObject();
            if (file != null) {
                buffer = createMappedBuffer(file, capacity, false);
            } else {
                if (direct) {
                    elements = ByteBuffer.allocateDirect(Character.SIZE / Byte.SIZE * capacity).asCharBuffer();
                } else {
                    elements = CharBuffer.allocate(capacity);
                }
                elements.limit(length);
                for (int i = 0; i < length; i++) {
                    elements.put(s.readChar());
                }
                elements.rewind();
            }
        }

        private Object readResolve() {
            BoundedCharBufferArrayImpl array = file == null
                    ? new BoundedCharBufferArrayImpl(elements, characteristics, false)
                    : new BoundedCharBufferArrayImpl(file, buffer, length);
            array.setClearReservedElements(clearReservedElements);
            return array;
        }
    }
}
TOP

Related Classes of org.squarebrackets.BoundedCharBufferArrayImpl$SubBoundedCharBufferArrayImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.