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