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