Home | History | Annotate | Download | only in nio
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package java.nio;
     19 
     20 import java.util.Arrays;
     21 
     22 /**
     23  * A buffer of doubles.
     24  * <p>
     25  * A double buffer can be created in either one of the following ways:
     26  * <ul>
     27  * <li>{@link #allocate(int) Allocate} a new double array and create a buffer
     28  * based on it;</li>
     29  * <li>{@link #wrap(double[]) Wrap} an existing double array to create a new
     30  * buffer;</li>
     31  * <li>Use
     32  * {@link java.nio.ByteBuffer#asDoubleBuffer() ByteBuffer.asDoubleBuffer} to
     33  * create a double buffer based on a byte buffer.</li>
     34  * </ul>
     35  */
     36 public abstract class DoubleBuffer extends Buffer implements
     37         Comparable<DoubleBuffer> {
     38 
     39     /**
     40      * Creates a double buffer based on a newly allocated double array.
     41      *
     42      * @param capacity
     43      *            the capacity of the new buffer.
     44      * @return the created double buffer.
     45      * @throws IllegalArgumentException
     46      *             if {@code capacity} is less than zero.
     47      */
     48     public static DoubleBuffer allocate(int capacity) {
     49         if (capacity < 0) {
     50             throw new IllegalArgumentException("capacity < 0: " + capacity);
     51         }
     52         return new DoubleArrayBuffer(new double[capacity]);
     53     }
     54 
     55     /**
     56      * Creates a new double buffer by wrapping the given double array.
     57      * <p>
     58      * Calling this method has the same effect as
     59      * {@code wrap(array, 0, array.length)}.
     60      *
     61      * @param array
     62      *            the double array which the new buffer will be based on.
     63      * @return the created double buffer.
     64      */
     65     public static DoubleBuffer wrap(double[] array) {
     66         return wrap(array, 0, array.length);
     67     }
     68 
     69     /**
     70      * Creates a new double buffer by wrapping the given double array.
     71      * <p>
     72      * The new buffer's position will be {@code start}, limit will be
     73      * {@code start + doubleCount}, capacity will be the length of the array.
     74      *
     75      * @param array
     76      *            the double array which the new buffer will be based on.
     77      * @param start
     78      *            the start index, must not be negative and not greater than
     79      *            {@code array.length}.
     80      * @param doubleCount
     81      *            the length, must not be negative and not greater than
     82      *            {@code array.length - start}.
     83      * @return the created double buffer.
     84      * @throws IndexOutOfBoundsException
     85      *                if either {@code start} or {@code doubleCount} is invalid.
     86      */
     87     public static DoubleBuffer wrap(double[] array, int start, int doubleCount) {
     88         Arrays.checkOffsetAndCount(array.length, start, doubleCount);
     89         DoubleBuffer buf = new DoubleArrayBuffer(array);
     90         buf.position = start;
     91         buf.limit = start + doubleCount;
     92         return buf;
     93     }
     94 
     95     DoubleBuffer(int capacity, long effectiveDirectAddress) {
     96         super(3, capacity, effectiveDirectAddress);
     97     }
     98 
     99     public final double[] array() {
    100         return protectedArray();
    101     }
    102 
    103     public final int arrayOffset() {
    104         return protectedArrayOffset();
    105     }
    106 
    107     /**
    108      * Returns a read-only buffer that shares its content with this buffer.
    109      * <p>
    110      * The returned buffer is guaranteed to be a new instance, even if this
    111      * buffer is read-only itself. The new buffer's position, limit, capacity
    112      * and mark are the same as this buffer's.
    113      * <p>
    114      * The new buffer shares its content with this buffer, which means that this
    115      * buffer's change of content will be visible to the new buffer. The two
    116      * buffer's position, limit and mark are independent.
    117      *
    118      * @return a read-only version of this buffer.
    119      */
    120     public abstract DoubleBuffer asReadOnlyBuffer();
    121 
    122     /**
    123      * Compacts this double buffer.
    124      * <p>
    125      * The remaining doubles will be moved to the head of the buffer, staring
    126      * from position zero. Then the position is set to {@code remaining()}; the
    127      * limit is set to capacity; the mark is cleared.
    128      *
    129      * @return this buffer.
    130      * @throws ReadOnlyBufferException
    131      *                if no changes may be made to the contents of this buffer.
    132      */
    133     public abstract DoubleBuffer compact();
    134 
    135     /**
    136      * Compare the remaining doubles of this buffer to another double buffer's
    137      * remaining doubles.
    138      *
    139      * @param otherBuffer
    140      *            another double buffer.
    141      * @return a negative value if this is less than {@code other}; 0 if this
    142      *         equals to {@code other}; a positive value if this is greater
    143      *         than {@code other}.
    144      * @throws ClassCastException
    145      *                if {@code other} is not a double buffer.
    146      */
    147     public int compareTo(DoubleBuffer otherBuffer) {
    148         int compareRemaining = (remaining() < otherBuffer.remaining()) ? remaining()
    149                 : otherBuffer.remaining();
    150         int thisPos = position;
    151         int otherPos = otherBuffer.position;
    152         double thisDouble, otherDouble;
    153         while (compareRemaining > 0) {
    154             thisDouble = get(thisPos);
    155             otherDouble = otherBuffer.get(otherPos);
    156             // checks for double and NaN inequality
    157             if ((thisDouble != otherDouble)
    158                     && ((thisDouble == thisDouble) || (otherDouble == otherDouble))) {
    159                 return thisDouble < otherDouble ? -1 : 1;
    160             }
    161             thisPos++;
    162             otherPos++;
    163             compareRemaining--;
    164         }
    165         return remaining() - otherBuffer.remaining();
    166     }
    167 
    168     /**
    169      * Returns a duplicated buffer that shares its content with this buffer.
    170      * <p>
    171      * The duplicated buffer's position, limit, capacity and mark are the same
    172      * as this buffer's. The duplicated buffer's read-only property and byte
    173      * order are the same as this buffer's, too.
    174      * <p>
    175      * The new buffer shares its content with this buffer, which means either
    176      * buffer's change of content will be visible to the other. The two buffers'
    177      * position, limit and mark are independent.
    178      */
    179     public abstract DoubleBuffer duplicate();
    180 
    181     /**
    182      * Checks whether this double buffer is equal to another object. If {@code
    183      * other} is not a {@code DoubleBuffer} then {@code false} is returned.
    184      *
    185      * <p>Two double buffers are equal if their remaining doubles are equal.
    186      * Position, limit, capacity and mark are not considered.
    187      *
    188      * <p>This method considers two doubles {@code a} and {@code b} to be equal
    189      * if {@code a == b} or if {@code a} and {@code b} are both {@code NaN}.
    190      * Unlike {@link Double#equals}, this method considers {@code -0.0} and
    191      * {@code +0.0} to be equal.
    192      *
    193      * @param other
    194      *            the object to compare with this double buffer.
    195      * @return {@code true} if this double buffer is equal to {@code other},
    196      *         {@code false} otherwise.
    197      */
    198     @Override
    199     public boolean equals(Object other) {
    200         if (!(other instanceof DoubleBuffer)) {
    201             return false;
    202         }
    203         DoubleBuffer otherBuffer = (DoubleBuffer) other;
    204 
    205         if (remaining() != otherBuffer.remaining()) {
    206             return false;
    207         }
    208 
    209         int myPosition = position;
    210         int otherPosition = otherBuffer.position;
    211         boolean equalSoFar = true;
    212         while (equalSoFar && (myPosition < limit)) {
    213             double a = get(myPosition++);
    214             double b = otherBuffer.get(otherPosition++);
    215             equalSoFar = a == b || (a != a && b != b);
    216         }
    217 
    218         return equalSoFar;
    219     }
    220 
    221     /**
    222      * Returns the double at the current position and increases the position by
    223      * 1.
    224      *
    225      * @return the double at the current position.
    226      * @throws BufferUnderflowException
    227      *                if the position is equal or greater than limit.
    228      */
    229     public abstract double get();
    230 
    231     /**
    232      * Reads doubles from the current position into the specified double array
    233      * and increases the position by the number of doubles read.
    234      * <p>
    235      * Calling this method has the same effect as
    236      * {@code get(dst, 0, dst.length)}.
    237      *
    238      * @param dst
    239      *            the destination double array.
    240      * @return this buffer.
    241      * @throws BufferUnderflowException
    242      *                if {@code dst.length} is greater than {@code remaining()}.
    243      */
    244     public DoubleBuffer get(double[] dst) {
    245         return get(dst, 0, dst.length);
    246     }
    247 
    248     /**
    249      * Reads doubles from the current position into the specified double array,
    250      * starting from the specified offset, and increases the position by the
    251      * number of doubles read.
    252      *
    253      * @param dst
    254      *            the target double array.
    255      * @param dstOffset
    256      *            the offset of the double array, must not be negative and not
    257      *            greater than {@code dst.length}.
    258      * @param doubleCount
    259      *            the number of doubles to read, must be no less than zero and
    260      *            not greater than {@code dst.length - dstOffset}.
    261      * @return this buffer.
    262      * @throws IndexOutOfBoundsException
    263      *                if either {@code dstOffset} or {@code doubleCount} is invalid.
    264      * @throws BufferUnderflowException
    265      *                if {@code doubleCount} is greater than {@code remaining()}.
    266      */
    267     public DoubleBuffer get(double[] dst, int dstOffset, int doubleCount) {
    268         Arrays.checkOffsetAndCount(dst.length, dstOffset, doubleCount);
    269         if (doubleCount > remaining()) {
    270             throw new BufferUnderflowException();
    271         }
    272         for (int i = dstOffset; i < dstOffset + doubleCount; ++i) {
    273             dst[i] = get();
    274         }
    275         return this;
    276     }
    277 
    278     /**
    279      * Returns a double at the specified index; the position is not changed.
    280      *
    281      * @param index
    282      *            the index, must not be negative and less than limit.
    283      * @return a double at the specified index.
    284      * @throws IndexOutOfBoundsException
    285      *                if index is invalid.
    286      */
    287     public abstract double get(int index);
    288 
    289     public final boolean hasArray() {
    290         return protectedHasArray();
    291     }
    292 
    293     /**
    294      * Calculates this buffer's hash code from the remaining chars. The
    295      * position, limit, capacity and mark don't affect the hash code.
    296      *
    297      * @return the hash code calculated from the remaining chars.
    298      */
    299     @Override
    300     public int hashCode() {
    301         int myPosition = position;
    302         int hash = 0;
    303         long l;
    304         while (myPosition < limit) {
    305             l = Double.doubleToLongBits(get(myPosition++));
    306             hash = hash + ((int) l) ^ ((int) (l >> 32));
    307         }
    308         return hash;
    309     }
    310 
    311     /**
    312      * Indicates whether this buffer is direct. A direct buffer will try its
    313      * best to take advantage of native memory APIs and it may not stay in the
    314      * Java heap, so it is not affected by garbage collection.
    315      * <p>
    316      * A double buffer is direct if it is based on a byte buffer and the byte
    317      * buffer is direct.
    318      *
    319      * @return {@code true} if this buffer is direct, {@code false} otherwise.
    320      */
    321     public abstract boolean isDirect();
    322 
    323     /**
    324      * Returns the byte order used by this buffer when converting doubles
    325      * from/to bytes.
    326      * <p>
    327      * If this buffer is not based on a byte buffer, then this always returns
    328      * the platform's native byte order.
    329      *
    330      * @return the byte order used by this buffer when converting doubles
    331      *         from/to bytes.
    332      */
    333     public abstract ByteOrder order();
    334 
    335     /**
    336      * Child class implements this method to realize {@code array()}.
    337      *
    338      * @see #array()
    339      */
    340     abstract double[] protectedArray();
    341 
    342     /**
    343      * Child class implements this method to realize {@code arrayOffset()}.
    344      *
    345      * @see #arrayOffset()
    346      */
    347     abstract int protectedArrayOffset();
    348 
    349     /**
    350      * Child class implements this method to realize {@code hasArray()}.
    351      *
    352      * @see #hasArray()
    353      */
    354     abstract boolean protectedHasArray();
    355 
    356     /**
    357      * Writes the given double to the current position and increases the
    358      * position by 1.
    359      *
    360      * @param d
    361      *            the double to write.
    362      * @return this buffer.
    363      * @throws BufferOverflowException
    364      *                if position is equal or greater than limit.
    365      * @throws ReadOnlyBufferException
    366      *                if no changes may be made to the contents of this buffer.
    367      */
    368     public abstract DoubleBuffer put(double d);
    369 
    370     /**
    371      * Writes doubles from the given double array to the current position and
    372      * increases the position by the number of doubles written.
    373      * <p>
    374      * Calling this method has the same effect as
    375      * {@code put(src, 0, src.length)}.
    376      *
    377      * @param src
    378      *            the source double array.
    379      * @return this buffer.
    380      * @throws BufferOverflowException
    381      *                if {@code remaining()} is less than {@code src.length}.
    382      * @throws ReadOnlyBufferException
    383      *                if no changes may be made to the contents of this buffer.
    384      */
    385     public final DoubleBuffer put(double[] src) {
    386         return put(src, 0, src.length);
    387     }
    388 
    389     /**
    390      * Writes doubles from the given double array, starting from the specified
    391      * offset, to the current position and increases the position by the number
    392      * of doubles written.
    393      *
    394      * @param src
    395      *            the source double array.
    396      * @param srcOffset
    397      *            the offset of double array, must not be negative and not
    398      *            greater than {@code src.length}.
    399      * @param doubleCount
    400      *            the number of doubles to write, must be no less than zero and
    401      *            not greater than {@code src.length - srcOffset}.
    402      * @return this buffer.
    403      * @throws BufferOverflowException
    404      *                if {@code remaining()} is less than {@code doubleCount}.
    405      * @throws IndexOutOfBoundsException
    406      *                if either {@code srcOffset} or {@code doubleCount} is invalid.
    407      * @throws ReadOnlyBufferException
    408      *                if no changes may be made to the contents of this buffer.
    409      */
    410     public DoubleBuffer put(double[] src, int srcOffset, int doubleCount) {
    411         Arrays.checkOffsetAndCount(src.length, srcOffset, doubleCount);
    412         if (doubleCount > remaining()) {
    413             throw new BufferOverflowException();
    414         }
    415         for (int i = srcOffset; i < srcOffset + doubleCount; ++i) {
    416             put(src[i]);
    417         }
    418         return this;
    419     }
    420 
    421     /**
    422      * Writes all the remaining doubles of the {@code src} double buffer to this
    423      * buffer's current position, and increases both buffers' position by the
    424      * number of doubles copied.
    425      *
    426      * @param src
    427      *            the source double buffer.
    428      * @return this buffer.
    429      * @throws BufferOverflowException
    430      *                if {@code src.remaining()} is greater than this buffer's
    431      *                {@code remaining()}.
    432      * @throws IllegalArgumentException
    433      *                if {@code src} is this buffer.
    434      * @throws ReadOnlyBufferException
    435      *                if no changes may be made to the contents of this buffer.
    436      */
    437     public DoubleBuffer put(DoubleBuffer src) {
    438         if (isReadOnly()) {
    439             throw new ReadOnlyBufferException();
    440         }
    441         if (src == this) {
    442             throw new IllegalArgumentException("src == this");
    443         }
    444         if (src.remaining() > remaining()) {
    445             throw new BufferOverflowException();
    446         }
    447         double[] doubles = new double[src.remaining()];
    448         src.get(doubles);
    449         put(doubles);
    450         return this;
    451     }
    452 
    453     /**
    454      * Write a double to the specified index of this buffer and the position is
    455      * not changed.
    456      *
    457      * @param index
    458      *            the index, must not be negative and less than the limit.
    459      * @param d
    460      *            the double to write.
    461      * @return this buffer.
    462      * @throws IndexOutOfBoundsException
    463      *                if index is invalid.
    464      * @throws ReadOnlyBufferException
    465      *                if no changes may be made to the contents of this buffer.
    466      */
    467     public abstract DoubleBuffer put(int index, double d);
    468 
    469     /**
    470      * Returns a sliced buffer that shares its content with this buffer.
    471      * <p>
    472      * The sliced buffer's capacity will be this buffer's {@code remaining()},
    473      * and its zero position will correspond to this buffer's current position.
    474      * The new buffer's position will be 0, limit will be its capacity, and its
    475      * mark is cleared. The new buffer's read-only property and byte order are
    476      * the same as this buffer's.
    477      * <p>
    478      * The new buffer shares its content with this buffer, which means either
    479      * buffer's change of content will be visible to the other. The two buffers'
    480      * position, limit and mark are independent.
    481      */
    482     public abstract DoubleBuffer slice();
    483 }
    484