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