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 ShortArrayBuffer(new short[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 ShortArrayBuffer(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 buffers'
174     * position, limit and mark are independent.
175     */
176    public abstract ShortBuffer duplicate();
177
178    /**
179     * Checks whether this short buffer is equal to another object.
180     * <p>
181     * If {@code other} is not a short buffer then {@code false} is returned.
182     * Two short buffers are equal if and only if their remaining shorts are
183     * exactly the same. Position, limit, capacity and mark are not considered.
184     *
185     * @param other
186     *            the object to compare with this short buffer.
187     * @return {@code true} if this short buffer is equal to {@code other},
188     *         {@code false} otherwise.
189     */
190    @Override
191    public boolean equals(Object other) {
192        if (!(other instanceof ShortBuffer)) {
193            return false;
194        }
195        ShortBuffer otherBuffer = (ShortBuffer) other;
196
197        if (remaining() != otherBuffer.remaining()) {
198            return false;
199        }
200
201        int myPosition = position;
202        int otherPosition = otherBuffer.position;
203        boolean equalSoFar = true;
204        while (equalSoFar && (myPosition < limit)) {
205            equalSoFar = get(myPosition++) == otherBuffer.get(otherPosition++);
206        }
207
208        return equalSoFar;
209    }
210
211    /**
212     * Returns the short at the current position and increases the position by
213     * 1.
214     *
215     * @return the short at the current position.
216     * @exception BufferUnderflowException
217     *                if the position is equal or greater than limit.
218     */
219    public abstract short get();
220
221    /**
222     * Reads shorts from the current position into the specified short array and
223     * increases the position by the number of shorts read.
224     * <p>
225     * Calling this method has the same effect as
226     * {@code get(dst, 0, dst.length)}.
227     *
228     * @param dst
229     *            the destination short array.
230     * @return this buffer.
231     * @exception BufferUnderflowException
232     *                if {@code dst.length} is greater than {@code remaining()}.
233     */
234    public ShortBuffer get(short[] dst) {
235        return get(dst, 0, dst.length);
236    }
237
238    /**
239     * Reads shorts from the current position into the specified short array,
240     * starting from the specified offset, and increases the position by the
241     * number of shorts read.
242     *
243     * @param dst
244     *            the target short array.
245     * @param dstOffset
246     *            the offset of the short array, must not be negative and not
247     *            greater than {@code dst.length}.
248     * @param shortCount
249     *            the number of shorts to read, must be no less than zero and
250     *            not greater than {@code dst.length - dstOffset}.
251     * @return this buffer.
252     * @exception IndexOutOfBoundsException
253     *                if either {@code dstOffset} or {@code shortCount} is invalid.
254     * @exception BufferUnderflowException
255     *                if {@code shortCount} is greater than {@code remaining()}.
256     */
257    public ShortBuffer get(short[] dst, int dstOffset, int shortCount) {
258        Arrays.checkOffsetAndCount(dst.length, dstOffset, shortCount);
259        if (shortCount > remaining()) {
260            throw new BufferUnderflowException();
261        }
262        for (int i = dstOffset; i < dstOffset + shortCount; ++i) {
263            dst[i] = get();
264        }
265        return this;
266    }
267
268    /**
269     * Returns the short at the specified index; the position is not changed.
270     *
271     * @param index
272     *            the index, must not be negative and less than limit.
273     * @return a short at the specified index.
274     * @exception IndexOutOfBoundsException
275     *                if index is invalid.
276     */
277    public abstract short get(int index);
278
279    public final boolean hasArray() {
280        return protectedHasArray();
281    }
282
283    /**
284     * Calculates this buffer's hash code from the remaining chars. The
285     * position, limit, capacity and mark don't affect the hash code.
286     *
287     * @return the hash code calculated from the remaining shorts.
288     */
289    @Override
290    public int hashCode() {
291        int myPosition = position;
292        int hash = 0;
293        while (myPosition < limit) {
294            hash = hash + get(myPosition++);
295        }
296        return hash;
297    }
298
299    /**
300     * Indicates whether this buffer is direct. A direct buffer will try its
301     * best to take advantage of native memory APIs and it may not stay in the
302     * Java heap, so it is not affected by garbage collection.
303     * <p>
304     * A short buffer is direct if it is based on a byte buffer and the byte
305     * buffer is direct.
306     *
307     * @return {@code true} if this buffer is direct, {@code false} otherwise.
308     */
309    public abstract boolean isDirect();
310
311    /**
312     * Returns the byte order used by this buffer when converting shorts from/to
313     * bytes.
314     * <p>
315     * If this buffer is not based on a byte buffer, then always return the
316     * platform's native byte order.
317     *
318     * @return the byte order used by this buffer when converting shorts from/to
319     *         bytes.
320     */
321    public abstract ByteOrder order();
322
323    /**
324     * Child class implements this method to realize {@code array()}.
325     *
326     * @return see {@code array()}
327     */
328    abstract short[] protectedArray();
329
330    /**
331     * Child class implements this method to realize {@code arrayOffset()}.
332     *
333     * @return see {@code arrayOffset()}
334     */
335    abstract int protectedArrayOffset();
336
337    /**
338     * Child class implements this method to realize {@code hasArray()}.
339     *
340     * @return see {@code hasArray()}
341     */
342    abstract boolean protectedHasArray();
343
344    /**
345     * Writes the given short to the current position and increases the position
346     * by 1.
347     *
348     * @param s
349     *            the short to write.
350     * @return this buffer.
351     * @exception BufferOverflowException
352     *                if position is equal or greater than limit.
353     * @exception ReadOnlyBufferException
354     *                if no changes may be made to the contents of this buffer.
355     */
356    public abstract ShortBuffer put(short s);
357
358    /**
359     * Writes shorts from the given short array to the current position and
360     * increases the position by the number of shorts written.
361     * <p>
362     * Calling this method has the same effect as
363     * {@code put(src, 0, src.length)}.
364     *
365     * @param src
366     *            the source short array.
367     * @return this buffer.
368     * @exception BufferOverflowException
369     *                if {@code remaining()} is less than {@code src.length}.
370     * @exception ReadOnlyBufferException
371     *                if no changes may be made to the contents of this buffer.
372     */
373    public final ShortBuffer put(short[] src) {
374        return put(src, 0, src.length);
375    }
376
377    /**
378     * Writes shorts from the given short array, starting from the specified
379     * offset, to the current position and increases the position by the number
380     * of shorts written.
381     *
382     * @param src
383     *            the source short array.
384     * @param srcOffset
385     *            the offset of short array, must not be negative and not
386     *            greater than {@code src.length}.
387     * @param shortCount
388     *            the number of shorts to write, must be no less than zero and
389     *            not greater than {@code src.length - srcOffset}.
390     * @return this buffer.
391     * @exception BufferOverflowException
392     *                if {@code remaining()} is less than {@code shortCount}.
393     * @exception IndexOutOfBoundsException
394     *                if either {@code srcOffset} or {@code shortCount} is invalid.
395     * @exception ReadOnlyBufferException
396     *                if no changes may be made to the contents of this buffer.
397     */
398    public ShortBuffer put(short[] src, int srcOffset, int shortCount) {
399        Arrays.checkOffsetAndCount(src.length, srcOffset, shortCount);
400        if (shortCount > remaining()) {
401            throw new BufferOverflowException();
402        }
403        for (int i = srcOffset; i < srcOffset + shortCount; ++i) {
404            put(src[i]);
405        }
406        return this;
407    }
408
409    /**
410     * Writes all the remaining shorts of the {@code src} short buffer to this
411     * buffer's current position, and increases both buffers' position by the
412     * number of shorts copied.
413     *
414     * @param src
415     *            the source short buffer.
416     * @return this buffer.
417     * @exception BufferOverflowException
418     *                if {@code src.remaining()} is greater than this buffer's
419     *                {@code remaining()}.
420     * @exception IllegalArgumentException
421     *                if {@code src} is this buffer.
422     * @exception ReadOnlyBufferException
423     *                if no changes may be made to the contents of this buffer.
424     */
425    public ShortBuffer put(ShortBuffer src) {
426        if (isReadOnly()) {
427            throw new ReadOnlyBufferException();
428        }
429        if (src == this) {
430            throw new IllegalArgumentException("src == this");
431        }
432        if (src.remaining() > remaining()) {
433            throw new BufferOverflowException();
434        }
435        short[] contents = new short[src.remaining()];
436        src.get(contents);
437        put(contents);
438        return this;
439    }
440
441    /**
442     * Writes a short to the specified index of this buffer; the position is not
443     * changed.
444     *
445     * @param index
446     *            the index, must not be negative and less than the limit.
447     * @param s
448     *            the short to write.
449     * @return this buffer.
450     * @exception IndexOutOfBoundsException
451     *                if index is invalid.
452     * @exception ReadOnlyBufferException
453     *                if no changes may be made to the contents of this buffer.
454     */
455    public abstract ShortBuffer put(int index, short s);
456
457    /**
458     * Returns a sliced buffer that shares its content with this buffer.
459     * <p>
460     * The sliced buffer's capacity will be this buffer's {@code remaining()},
461     * and its zero position will correspond to this buffer's current position.
462     * The new buffer's position will be 0, limit will be its capacity, and its
463     * mark is cleared. The new buffer's read-only property and byte order are
464     * same as this buffer's.
465     * <p>
466     * The new buffer shares its content with this buffer, which means either
467     * buffer's change of content will be visible to the other. The two buffers'
468     * position, limit and mark are independent.
469     */
470    public abstract ShortBuffer slice();
471}
472