001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with this
004 * work for additional information regarding copyright ownership. The ASF
005 * licenses this file to you under the Apache License, Version 2.0 (the
006 * "License"); you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014 * License for the specific language governing permissions and limitations
015 * under the License.
016 */
017package org.apache.hadoop.hbase.util;
018
019import java.io.ByteArrayOutputStream;
020import java.io.DataInput;
021import java.io.DataInputStream;
022import java.io.DataOutput;
023import java.io.IOException;
024import java.io.InputStream;
025import java.io.OutputStream;
026import java.math.BigDecimal;
027import java.math.BigInteger;
028import java.nio.ByteBuffer;
029import java.util.Arrays;
030
031import org.apache.hadoop.hbase.io.ByteBufferWriter;
032import org.apache.hadoop.hbase.io.util.StreamUtils;
033import org.apache.hadoop.io.IOUtils;
034import org.apache.hadoop.io.WritableUtils;
035import org.apache.yetus.audience.InterfaceAudience;
036import sun.nio.ch.DirectBuffer;
037
038import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
039
040/**
041 * Utility functions for working with byte buffers, such as reading/writing
042 * variable-length long numbers.
043 */
044@SuppressWarnings("restriction")
045@InterfaceAudience.Public
046public final class ByteBufferUtils {
047  // "Compressed integer" serialization helper constants.
048  public final static int VALUE_MASK = 0x7f;
049  public final static int NEXT_BIT_SHIFT = 7;
050  public final static int NEXT_BIT_MASK = 1 << 7;
051  @VisibleForTesting
052  final static boolean UNSAFE_AVAIL = UnsafeAvailChecker.isAvailable();
053  public final static boolean UNSAFE_UNALIGNED = UnsafeAvailChecker.unaligned();
054
055  private ByteBufferUtils() {
056  }
057
058  /**
059   * Similar to {@link WritableUtils#writeVLong(java.io.DataOutput, long)},
060   * but writes to a {@link ByteBuffer}.
061   */
062  public static void writeVLong(ByteBuffer out, long i) {
063    if (i >= -112 && i <= 127) {
064      out.put((byte) i);
065      return;
066    }
067
068    int len = -112;
069    if (i < 0) {
070      i ^= -1L; // take one's complement
071      len = -120;
072    }
073
074    long tmp = i;
075    while (tmp != 0) {
076      tmp = tmp >> 8;
077      len--;
078    }
079
080    out.put((byte) len);
081
082    len = (len < -120) ? -(len + 120) : -(len + 112);
083
084    for (int idx = len; idx != 0; idx--) {
085      int shiftbits = (idx - 1) * 8;
086      long mask = 0xFFL << shiftbits;
087      out.put((byte) ((i & mask) >> shiftbits));
088    }
089  }
090
091  /**
092   * Similar to {@link WritableUtils#readVLong(DataInput)} but reads from a
093   * {@link ByteBuffer}.
094   */
095  public static long readVLong(ByteBuffer in) {
096    byte firstByte = in.get();
097    int len = WritableUtils.decodeVIntSize(firstByte);
098    if (len == 1) {
099      return firstByte;
100    }
101    long i = 0;
102    for (int idx = 0; idx < len-1; idx++) {
103      byte b = in.get();
104      i = i << 8;
105      i = i | (b & 0xFF);
106    }
107    return (WritableUtils.isNegativeVInt(firstByte) ? (i ^ -1L) : i);
108  }
109
110
111  /**
112   * Put in buffer integer using 7 bit encoding. For each written byte:
113   * 7 bits are used to store value
114   * 1 bit is used to indicate whether there is next bit.
115   * @param value Int to be compressed.
116   * @param out Where to put compressed data
117   * @return Number of bytes written.
118   * @throws IOException on stream error
119   */
120   public static int putCompressedInt(OutputStream out, final int value)
121      throws IOException {
122    int i = 0;
123    int tmpvalue = value;
124    do {
125      byte b = (byte) (tmpvalue & VALUE_MASK);
126      tmpvalue >>>= NEXT_BIT_SHIFT;
127      if (tmpvalue != 0) {
128        b |= (byte) NEXT_BIT_MASK;
129      }
130      out.write(b);
131      i++;
132    } while (tmpvalue != 0);
133    return i;
134  }
135
136   /**
137    * Put in output stream 32 bit integer (Big Endian byte order).
138    * @param out Where to put integer.
139    * @param value Value of integer.
140    * @throws IOException On stream error.
141    */
142   public static void putInt(OutputStream out, final int value)
143       throws IOException {
144     // We have writeInt in ByteBufferOutputStream so that it can directly write
145     // int to underlying
146     // ByteBuffer in one step.
147     if (out instanceof ByteBufferWriter) {
148       ((ByteBufferWriter) out).writeInt(value);
149     } else {
150       StreamUtils.writeInt(out, value);
151     }
152   }
153
154  public static byte toByte(ByteBuffer buffer, int offset) {
155    if (UNSAFE_AVAIL) {
156      return UnsafeAccess.toByte(buffer, offset);
157    } else {
158      return buffer.get(offset);
159    }
160  }
161
162  /**
163   * Copy the data to the output stream and update position in buffer.
164   * @param out the stream to write bytes to
165   * @param in the buffer to read bytes from
166   * @param length the number of bytes to copy
167   */
168  public static void moveBufferToStream(OutputStream out, ByteBuffer in,
169      int length) throws IOException {
170    copyBufferToStream(out, in, in.position(), length);
171    skip(in, length);
172  }
173
174  /**
175   * Copy data from a buffer to an output stream. Does not update the position
176   * in the buffer.
177   * @param out the stream to write bytes to
178   * @param in the buffer to read bytes from
179   * @param offset the offset in the buffer (from the buffer's array offset)
180   *      to start copying bytes from
181   * @param length the number of bytes to copy
182   */
183  public static void copyBufferToStream(OutputStream out, ByteBuffer in,
184      int offset, int length) throws IOException {
185    if (out instanceof ByteBufferWriter) {
186      ((ByteBufferWriter) out).write(in, offset, length);
187    } else if (in.hasArray()) {
188      out.write(in.array(), in.arrayOffset() + offset, length);
189    } else {
190      for (int i = 0; i < length; ++i) {
191        out.write(toByte(in, offset + i));
192      }
193    }
194  }
195
196  /**
197   * Copy data from a buffer to an output stream. Does not update the position
198   * in the buffer.
199   * @param out the output stream to write bytes to
200   * @param in the buffer to read bytes from
201   * @param offset the offset in the buffer (from the buffer's array offset)
202   *      to start copying bytes from
203   * @param length the number of bytes to copy
204   */
205  public static void copyBufferToStream(DataOutput out, ByteBuffer in, int offset, int length)
206      throws IOException {
207    if (out instanceof ByteBufferWriter) {
208      ((ByteBufferWriter) out).write(in, offset, length);
209    } else if (in.hasArray()) {
210      out.write(in.array(), in.arrayOffset() + offset, length);
211    } else {
212      for (int i = 0; i < length; ++i) {
213        out.write(toByte(in, offset + i));
214      }
215    }
216  }
217
218  public static int putLong(OutputStream out, final long value,
219      final int fitInBytes) throws IOException {
220    long tmpValue = value;
221    for (int i = 0; i < fitInBytes; ++i) {
222      out.write((byte) (tmpValue & 0xff));
223      tmpValue >>>= 8;
224    }
225    return fitInBytes;
226  }
227
228  public static int putByte(ByteBuffer buffer, int offset, byte b) {
229    if (UNSAFE_AVAIL) {
230      return UnsafeAccess.putByte(buffer, offset, b);
231    } else {
232      buffer.put(offset, b);
233      return offset + 1;
234    }
235  }
236
237  /**
238   * Check how many bytes are required to store value.
239   * @param value Value which size will be tested.
240   * @return How many bytes are required to store value.
241   */
242  public static int longFitsIn(final long value) {
243    if (value < 0) {
244      return 8;
245    }
246
247    if (value < (1L << (4 * 8))) {
248      // no more than 4 bytes
249      if (value < (1L << (2 * 8))) {
250        if (value < (1L << (1 * 8))) {
251          return 1;
252        }
253        return 2;
254      }
255      if (value < (1L << (3 * 8))) {
256        return 3;
257      }
258      return 4;
259    }
260    // more than 4 bytes
261    if (value < (1L << (6 * 8))) {
262      if (value < (1L << (5 * 8))) {
263        return 5;
264      }
265      return 6;
266    }
267    if (value < (1L << (7 * 8))) {
268      return 7;
269    }
270    return 8;
271  }
272
273  /**
274   * Check how many bytes is required to store value.
275   * @param value Value which size will be tested.
276   * @return How many bytes are required to store value.
277   */
278  public static int intFitsIn(final int value) {
279    if (value < 0) {
280      return 4;
281    }
282
283    if (value < (1 << (2 * 8))) {
284      if (value < (1 << (1 * 8))) {
285        return 1;
286      }
287      return 2;
288    }
289    if (value <= (1 << (3 * 8))) {
290      return 3;
291    }
292    return 4;
293  }
294
295  /**
296   * Read integer from stream coded in 7 bits and increment position.
297   * @return the integer that has been read
298   * @throws IOException
299   */
300  public static int readCompressedInt(InputStream input)
301      throws IOException {
302    int result = 0;
303    int i = 0;
304    byte b;
305    do {
306      b = (byte) input.read();
307      result += (b & VALUE_MASK) << (NEXT_BIT_SHIFT * i);
308      i++;
309      if (i > Bytes.SIZEOF_INT + 1) {
310        throw new IllegalStateException(
311            "Corrupted compressed int (too long: " + (i + 1) + " bytes)");
312      }
313    } while (0 != (b & NEXT_BIT_MASK));
314    return result;
315  }
316
317  /**
318   * Read integer from buffer coded in 7 bits and increment position.
319   * @return Read integer.
320   */
321  public static int readCompressedInt(ByteBuffer buffer) {
322    byte b = buffer.get();
323    if ((b & NEXT_BIT_MASK) != 0) {
324      return (b & VALUE_MASK) + (readCompressedInt(buffer) << NEXT_BIT_SHIFT);
325    }
326    return b & VALUE_MASK;
327  }
328
329  /**
330   * Read long which was written to fitInBytes bytes and increment position.
331   * @param fitInBytes In how many bytes given long is stored.
332   * @return The value of parsed long.
333   * @throws IOException
334   */
335  public static long readLong(InputStream in, final int fitInBytes)
336      throws IOException {
337    long tmpLong = 0;
338    for (int i = 0; i < fitInBytes; ++i) {
339      tmpLong |= (in.read() & 0xffL) << (8 * i);
340    }
341    return tmpLong;
342  }
343
344  /**
345   * Read long which was written to fitInBytes bytes and increment position.
346   * @param fitInBytes In how many bytes given long is stored.
347   * @return The value of parsed long.
348   */
349  public static long readLong(ByteBuffer in, final int fitInBytes) {
350    long tmpLength = 0;
351    for (int i = 0; i < fitInBytes; ++i) {
352      tmpLength |= (in.get() & 0xffL) << (8L * i);
353    }
354    return tmpLength;
355  }
356
357  /**
358   * Copy the given number of bytes from the given stream and put it at the
359   * current position of the given buffer, updating the position in the buffer.
360   * @param out the buffer to write data to
361   * @param in the stream to read data from
362   * @param length the number of bytes to read/write
363   */
364  public static void copyFromStreamToBuffer(ByteBuffer out,
365      DataInputStream in, int length) throws IOException {
366    if (out.hasArray()) {
367      in.readFully(out.array(), out.position() + out.arrayOffset(),
368          length);
369      skip(out, length);
370    } else {
371      for (int i = 0; i < length; ++i) {
372        out.put(in.readByte());
373      }
374    }
375  }
376
377  /**
378   * Copy from the InputStream to a new heap ByteBuffer until the InputStream is exhausted.
379   */
380  public static ByteBuffer drainInputStreamToBuffer(InputStream is) throws IOException {
381    ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
382    IOUtils.copyBytes(is, baos, 4096, true);
383    ByteBuffer buffer = ByteBuffer.wrap(baos.toByteArray());
384    buffer.rewind();
385    return buffer;
386  }
387
388  /**
389   * Copy one buffer's whole data to another. Write starts at the current position of 'out' buffer.
390   * Note : This will advance the position marker of {@code out} and also change the position maker
391   * for {@code in}.
392   * @param in source buffer
393   * @param out destination buffer
394   */
395  public static void copyFromBufferToBuffer(ByteBuffer in, ByteBuffer out) {
396    if (in.hasArray() && out.hasArray()) {
397      int length = in.remaining();
398      System.arraycopy(in.array(), in.arrayOffset(), out.array(), out.arrayOffset(), length);
399      out.position(out.position() + length);
400      in.position(in.limit());
401    } else if (UNSAFE_AVAIL) {
402      int length = in.remaining();
403      UnsafeAccess.copy(in, in.position(), out, out.position(), length);
404      out.position(out.position() + length);
405      in.position(in.limit());
406    } else {
407      out.put(in);
408    }
409  }
410
411  /**
412   * Copy from one buffer to another from given offset. This will be absolute positional copying and
413   * won't affect the position of any of the buffers.
414   * @param in
415   * @param out
416   * @param sourceOffset
417   * @param destinationOffset
418   * @param length
419   */
420  public static void copyFromBufferToBuffer(ByteBuffer in, ByteBuffer out, int sourceOffset,
421      int destinationOffset, int length) {
422    if (in.hasArray() && out.hasArray()) {
423      System.arraycopy(in.array(), sourceOffset + in.arrayOffset(), out.array(), out.arrayOffset()
424          + destinationOffset, length);
425    } else if (UNSAFE_AVAIL) {
426      UnsafeAccess.copy(in, sourceOffset, out, destinationOffset, length);
427    } else {
428      ByteBuffer outDup = out.duplicate();
429      outDup.position(destinationOffset);
430      ByteBuffer inDup = in.duplicate();
431      inDup.position(sourceOffset).limit(sourceOffset + length);
432      outDup.put(inDup);
433    }
434    // We used to return a result but disabled; return destinationOffset + length;
435  }
436
437  /**
438   * Copy from one buffer to another from given offset.
439   * <p>
440   * Note : This will advance the position marker of {@code out} but not change the position maker
441   * for {@code in}
442   * @param in source buffer
443   * @param out destination buffer
444   * @param sourceOffset offset in the source buffer
445   * @param length how many bytes to copy
446   */
447  public static void copyFromBufferToBuffer(ByteBuffer in,
448      ByteBuffer out, int sourceOffset, int length) {
449    if (in.hasArray() && out.hasArray()) {
450      System.arraycopy(in.array(), sourceOffset + in.arrayOffset(), out.array(), out.position()
451          + out.arrayOffset(), length);
452      skip(out, length);
453    } else if (UNSAFE_AVAIL) {
454      UnsafeAccess.copy(in, sourceOffset, out, out.position(), length);
455      skip(out, length);
456    } else {
457      ByteBuffer inDup = in.duplicate();
458      inDup.position(sourceOffset).limit(sourceOffset + length);
459      out.put(inDup);
460    }
461  }
462
463  /**
464   * Find length of common prefix of two parts in the buffer
465   * @param buffer Where parts are located.
466   * @param offsetLeft Offset of the first part.
467   * @param offsetRight Offset of the second part.
468   * @param limit Maximal length of common prefix.
469   * @return Length of prefix.
470   */
471  public static int findCommonPrefix(ByteBuffer buffer, int offsetLeft,
472      int offsetRight, int limit) {
473    int prefix = 0;
474
475    for (; prefix < limit; ++prefix) {
476      if (buffer.get(offsetLeft + prefix) != buffer.get(offsetRight + prefix)) {
477        break;
478      }
479    }
480
481    return prefix;
482  }
483
484  /**
485   * Find length of common prefix in two arrays.
486   * @param left Array to be compared.
487   * @param leftOffset Offset in left array.
488   * @param leftLength Length of left array.
489   * @param right Array to be compared.
490   * @param rightOffset Offset in right array.
491   * @param rightLength Length of right array.
492   */
493  public static int findCommonPrefix(
494      byte[] left, int leftOffset, int leftLength,
495      byte[] right, int rightOffset, int rightLength) {
496    int length = Math.min(leftLength, rightLength);
497    int result = 0;
498
499    while (result < length &&
500        left[leftOffset + result] == right[rightOffset + result]) {
501      result++;
502    }
503
504    return result;
505  }
506
507  /**
508   * Find length of common prefix in two arrays.
509   * @param left ByteBuffer to be compared.
510   * @param leftOffset Offset in left ByteBuffer.
511   * @param leftLength Length of left ByteBuffer.
512   * @param right ByteBuffer to be compared.
513   * @param rightOffset Offset in right ByteBuffer.
514   * @param rightLength Length of right ByteBuffer.
515   */
516  public static int findCommonPrefix(ByteBuffer left, int leftOffset, int leftLength,
517      ByteBuffer right, int rightOffset, int rightLength) {
518    int length = Math.min(leftLength, rightLength);
519    int result = 0;
520
521    while (result < length && ByteBufferUtils.toByte(left, leftOffset + result) == ByteBufferUtils
522        .toByte(right, rightOffset + result)) {
523      result++;
524    }
525
526    return result;
527  }
528
529  /**
530   * Check whether two parts in the same buffer are equal.
531   * @param buffer In which buffer there are parts
532   * @param offsetLeft Beginning of first part.
533   * @param lengthLeft Length of the first part.
534   * @param offsetRight Beginning of the second part.
535   * @param lengthRight Length of the second part.
536   * @return True if equal
537   */
538  public static boolean arePartsEqual(ByteBuffer buffer,
539      int offsetLeft, int lengthLeft,
540      int offsetRight, int lengthRight) {
541    if (lengthLeft != lengthRight) {
542      return false;
543    }
544
545    if (buffer.hasArray()) {
546      return 0 == Bytes.compareTo(
547          buffer.array(), buffer.arrayOffset() + offsetLeft, lengthLeft,
548          buffer.array(), buffer.arrayOffset() + offsetRight, lengthRight);
549    }
550
551    for (int i = 0; i < lengthRight; ++i) {
552      if (buffer.get(offsetLeft + i) != buffer.get(offsetRight + i)) {
553        return false;
554      }
555    }
556    return true;
557  }
558
559  /**
560   * Increment position in buffer.
561   * @param buffer In this buffer.
562   * @param length By that many bytes.
563   */
564  public static void skip(ByteBuffer buffer, int length) {
565    buffer.position(buffer.position() + length);
566  }
567
568  public static void extendLimit(ByteBuffer buffer, int numBytes) {
569    buffer.limit(buffer.limit() + numBytes);
570  }
571
572  /**
573   * Copy the bytes from position to limit into a new byte[] of the exact length and sets the
574   * position and limit back to their original values (though not thread safe).
575   * @param buffer copy from here
576   * @param startPosition put buffer.get(startPosition) into byte[0]
577   * @return a new byte[] containing the bytes in the specified range
578   */
579  public static byte[] toBytes(ByteBuffer buffer, int startPosition) {
580    int originalPosition = buffer.position();
581    byte[] output = new byte[buffer.limit() - startPosition];
582    buffer.position(startPosition);
583    buffer.get(output);
584    buffer.position(originalPosition);
585    return output;
586  }
587
588  /**
589   * Copy the given number of bytes from specified offset into a new byte[]
590   * @param buffer
591   * @param offset
592   * @param length
593   * @return a new byte[] containing the bytes in the specified range
594   */
595  public static byte[] toBytes(ByteBuffer buffer, int offset, int length) {
596    byte[] output = new byte[length];
597    for (int i = 0; i < length; i++) {
598      output[i] = buffer.get(offset + i);
599    }
600    return output;
601  }
602
603  public static boolean equals(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
604    if ((l1 == 0) || (l2 == 0)) {
605      // both 0 length, return true, or else false
606      return l1 == l2;
607    }
608    // Since we're often comparing adjacent sorted data,
609    // it's usual to have equal arrays except for the very last byte
610    // so check that first
611    if (toByte(buf1, o1 + l1 - 1) != toByte(buf2, o2 + l2 - 1)) return false;
612    return compareTo(buf1, o1, l1, buf2, o2, l2) == 0;
613  }
614
615  /**
616   * @param buf
617   *          ByteBuffer to hash
618   * @param offset
619   *          offset to start from
620   * @param length
621   *          length to hash
622   */
623  public static int hashCode(ByteBuffer buf, int offset, int length) {
624    int hash = 1;
625    for (int i = offset; i < offset + length; i++) {
626      hash = (31 * hash) + (int) toByte(buf, i);
627    }
628    return hash;
629  }
630
631  public static int compareTo(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
632    // NOTE: This method is copied over in BBKVComparator!!!!! For perf reasons. If you make
633    // changes here, make them there too!!!!
634    if (UNSAFE_UNALIGNED) {
635      long offset1Adj, offset2Adj;
636      Object refObj1 = null, refObj2 = null;
637      if (buf1.isDirect()) {
638        offset1Adj = o1 + ((DirectBuffer) buf1).address();
639      } else {
640        offset1Adj = o1 + buf1.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
641        refObj1 = buf1.array();
642      }
643      if (buf2.isDirect()) {
644        offset2Adj = o2 + ((DirectBuffer) buf2).address();
645      } else {
646        offset2Adj = o2 + buf2.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
647        refObj2 = buf2.array();
648      }
649      return compareToUnsafe(refObj1, offset1Adj, l1, refObj2, offset2Adj, l2);
650    }
651    int end1 = o1 + l1;
652    int end2 = o2 + l2;
653    for (int i = o1, j = o2; i < end1 && j < end2; i++, j++) {
654      int a = buf1.get(i) & 0xFF;
655      int b = buf2.get(j) & 0xFF;
656      if (a != b) {
657        return a - b;
658      }
659    }
660    return l1 - l2;
661  }
662
663  public static boolean equals(ByteBuffer buf1, int o1, int l1, byte[] buf2, int o2, int l2) {
664    if ((l1 == 0) || (l2 == 0)) {
665      // both 0 length, return true, or else false
666      return l1 == l2;
667    }
668    // Since we're often comparing adjacent sorted data,
669    // it's usual to have equal arrays except for the very last byte
670    // so check that first
671    if (toByte(buf1, o1 + l1 - 1) != buf2[o2 + l2 - 1]) return false;
672    return compareTo(buf1, o1, l1, buf2, o2, l2) == 0;
673  }
674
675  // The below two methods show up in lots of places. Versions of them in commons util and in
676  // Cassandra. In guava too? They are copied from ByteBufferUtils. They are here as static
677  // privates. Seems to make code smaller and make Hotspot happier (comes of compares and study
678  // of compiled code via  jitwatch).
679
680  public static int compareTo(byte [] buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
681    if (UNSAFE_UNALIGNED) {
682      long offset2Adj;
683      Object refObj2 = null;
684      if (buf2.isDirect()) {
685        offset2Adj = o2 + ((DirectBuffer)buf2).address();
686      } else {
687        offset2Adj = o2 + buf2.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
688        refObj2 = buf2.array();
689      }
690      return compareToUnsafe(buf1, o1 + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET, l1,
691          refObj2, offset2Adj, l2);
692    }
693    int end1 = o1 + l1;
694    int end2 = o2 + l2;
695    for (int i = o1, j = o2; i < end1 && j < end2; i++, j++) {
696      int a = buf1[i] & 0xFF;
697      int b = buf2.get(j) & 0xFF;
698      if (a != b) {
699        return a - b;
700      }
701    }
702    return l1 - l2;
703  }
704
705  public static int compareTo(ByteBuffer buf1, int o1, int l1, byte[] buf2, int o2, int l2) {
706    if (UNSAFE_UNALIGNED) {
707      long offset1Adj;
708      Object refObj1 = null;
709      if (buf1.isDirect()) {
710        offset1Adj = o1 + ((DirectBuffer) buf1).address();
711      } else {
712        offset1Adj = o1 + buf1.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
713        refObj1 = buf1.array();
714      }
715      return compareToUnsafe(refObj1, offset1Adj, l1,
716          buf2, o2 + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET, l2);
717    }
718    int end1 = o1 + l1;
719    int end2 = o2 + l2;
720    for (int i = o1, j = o2; i < end1 && j < end2; i++, j++) {
721      int a = buf1.get(i) & 0xFF;
722      int b = buf2[j] & 0xFF;
723      if (a != b) {
724        return a - b;
725      }
726    }
727    return l1 - l2;
728  }
729
730  static int compareToUnsafe(Object obj1, long o1, int l1, Object obj2, long o2, int l2) {
731    final int stride = 8;
732    final int minLength = Math.min(l1, l2);
733    int strideLimit = minLength & ~(stride - 1);
734    int i;
735
736    /*
737     * Compare 8 bytes at a time. Benchmarking shows comparing 8 bytes at a time is no slower than
738     * comparing 4 bytes at a time even on 32-bit. On the other hand, it is substantially faster on
739     * 64-bit.
740     */
741    for (i = 0; i < strideLimit; i += stride) {
742      long lw = UnsafeAccess.theUnsafe.getLong(obj1, o1 + (long) i);
743      long rw = UnsafeAccess.theUnsafe.getLong(obj2, o2 + (long) i);
744      if (lw != rw) {
745        if (!UnsafeAccess.LITTLE_ENDIAN) {
746          return ((lw + Long.MIN_VALUE) < (rw + Long.MIN_VALUE)) ? -1 : 1;
747        }
748
749        /*
750         * We want to compare only the first index where left[index] != right[index]. This
751         * corresponds to the least significant nonzero byte in lw ^ rw, since lw and rw are
752         * little-endian. Long.numberOfTrailingZeros(diff) tells us the least significant
753         * nonzero bit, and zeroing out the first three bits of L.nTZ gives us the shift to get
754         * that least significant nonzero byte. This comparison logic is based on UnsignedBytes
755         * from guava v21
756         */
757        int n = Long.numberOfTrailingZeros(lw ^ rw) & ~0x7;
758        return ((int) ((lw >>> n) & 0xFF)) - ((int) ((rw >>> n) & 0xFF));
759      }
760    }
761
762    // The epilogue to cover the last (minLength % stride) elements.
763    for (; i < minLength; i++) {
764      int il = (UnsafeAccess.theUnsafe.getByte(obj1, o1 + i) & 0xFF);
765      int ir = (UnsafeAccess.theUnsafe.getByte(obj2, o2 + i) & 0xFF);
766      if (il != ir) {
767        return il - ir;
768      }
769    }
770    return l1 - l2;
771  }
772
773  /**
774   * Reads a short value at the given buffer's offset.
775   * @param buffer
776   * @param offset
777   * @return short value at offset
778   */
779  public static short toShort(ByteBuffer buffer, int offset) {
780    if (UNSAFE_UNALIGNED) {
781      return UnsafeAccess.toShort(buffer, offset);
782    } else {
783      return buffer.getShort(offset);
784    }
785  }
786
787  /**
788   * Reads an int value at the given buffer's current position. Also advances the buffer's position
789   */
790  public static int toInt(ByteBuffer buffer) {
791    if (UNSAFE_UNALIGNED) {
792      int i = UnsafeAccess.toInt(buffer, buffer.position());
793      buffer.position(buffer.position() + Bytes.SIZEOF_INT);
794      return i;
795    } else {
796      return buffer.getInt();
797    }
798  }
799
800  /**
801   * Reads an int value at the given buffer's offset.
802   * @param buffer
803   * @param offset
804   * @return int value at offset
805   */
806  public static int toInt(ByteBuffer buffer, int offset) {
807    if (UNSAFE_UNALIGNED) {
808      return UnsafeAccess.toInt(buffer, offset);
809    } else {
810      return buffer.getInt(offset);
811    }
812  }
813
814  /**
815   * Converts a ByteBuffer to an int value
816   *
817   * @param buf The ByteBuffer
818   * @param offset Offset to int value
819   * @param length Number of bytes used to store the int value.
820   * @return the int value
821   * @throws IllegalArgumentException
822   *           if there's not enough bytes left in the buffer after the given offset
823   */
824  public static int readAsInt(ByteBuffer buf, int offset, final int length) {
825    if (offset + length > buf.limit()) {
826      throw new IllegalArgumentException("offset (" + offset + ") + length (" + length
827          + ") exceed the" + " limit of the buffer: " + buf.limit());
828    }
829    int n = 0;
830    for(int i = offset; i < (offset + length); i++) {
831      n <<= 8;
832      n ^= toByte(buf, i) & 0xFF;
833    }
834    return n;
835  }
836
837  /**
838   * Reads a long value at the given buffer's offset.
839   * @param buffer
840   * @param offset
841   * @return long value at offset
842   */
843  public static long toLong(ByteBuffer buffer, int offset) {
844    if (UNSAFE_UNALIGNED) {
845      return UnsafeAccess.toLong(buffer, offset);
846    } else {
847      return buffer.getLong(offset);
848    }
849  }
850
851  /**
852   * Put an int value out to the given ByteBuffer's current position in big-endian format.
853   * This also advances the position in buffer by int size.
854   * @param buffer the ByteBuffer to write to
855   * @param val int to write out
856   */
857  public static void putInt(ByteBuffer buffer, int val) {
858    if (UNSAFE_UNALIGNED) {
859      int newPos = UnsafeAccess.putInt(buffer, buffer.position(), val);
860      buffer.position(newPos);
861    } else {
862      buffer.putInt(val);
863    }
864  }
865
866  public static int putInt(ByteBuffer buffer, int index, int val) {
867    if (UNSAFE_UNALIGNED) {
868      return UnsafeAccess.putInt(buffer, index, val);
869    }
870    buffer.putInt(index, val);
871    return index + Bytes.SIZEOF_INT;
872  }
873
874  /**
875   * Reads a double value at the given buffer's offset.
876   * @param buffer
877   * @param offset offset where double is
878   * @return double value at offset
879   */
880  public static double toDouble(ByteBuffer buffer, int offset) {
881    return Double.longBitsToDouble(toLong(buffer, offset));
882  }
883
884  /**
885   * Reads a BigDecimal value at the given buffer's offset.
886   * @param buffer
887   * @param offset
888   * @return BigDecimal value at offset
889   */
890  public static BigDecimal toBigDecimal(ByteBuffer buffer, int offset, int length) {
891    if (buffer == null || length < Bytes.SIZEOF_INT + 1 ||
892      (offset + length > buffer.limit())) {
893      return null;
894    }
895
896    int scale = toInt(buffer, offset);
897    byte[] tcBytes = new byte[length - Bytes.SIZEOF_INT];
898    copyFromBufferToArray(tcBytes, buffer, offset + Bytes.SIZEOF_INT, 0, length - Bytes.SIZEOF_INT);
899    return new BigDecimal(new BigInteger(tcBytes), scale);
900  }
901
902  /**
903   * Put a short value out to the given ByteBuffer's current position in big-endian format.
904   * This also advances the position in buffer by short size.
905   * @param buffer the ByteBuffer to write to
906   * @param val short to write out
907   */
908  public static void putShort(ByteBuffer buffer, short val) {
909    if (UNSAFE_UNALIGNED) {
910      int newPos = UnsafeAccess.putShort(buffer, buffer.position(), val);
911      buffer.position(newPos);
912    } else {
913      buffer.putShort(val);
914    }
915  }
916
917  public static int putShort(ByteBuffer buffer, int index, short val) {
918    if (UNSAFE_UNALIGNED) {
919      return UnsafeAccess.putShort(buffer, index, val);
920    }
921    buffer.putShort(index, val);
922    return index + Bytes.SIZEOF_SHORT;
923  }
924
925  public static int putAsShort(ByteBuffer buf, int index, int val) {
926    buf.put(index + 1, (byte) val);
927    val >>= 8;
928    buf.put(index, (byte) val);
929    return index + Bytes.SIZEOF_SHORT;
930  }
931
932  /**
933   * Put a long value out to the given ByteBuffer's current position in big-endian format.
934   * This also advances the position in buffer by long size.
935   * @param buffer the ByteBuffer to write to
936   * @param val long to write out
937   */
938  public static void putLong(ByteBuffer buffer, long val) {
939    if (UNSAFE_UNALIGNED) {
940      int newPos = UnsafeAccess.putLong(buffer, buffer.position(), val);
941      buffer.position(newPos);
942    } else {
943      buffer.putLong(val);
944    }
945  }
946
947  public static int putLong(ByteBuffer buffer, int index, long val) {
948    if (UNSAFE_UNALIGNED) {
949      return UnsafeAccess.putLong(buffer, index, val);
950    }
951    buffer.putLong(index, val);
952    return index + Bytes.SIZEOF_LONG;
953  }
954
955  /**
956   * Copies the bytes from given array's offset to length part into the given buffer. Puts the bytes
957   * to buffer's current position. This also advances the position in the 'out' buffer by 'length'
958   * @param out
959   * @param in
960   * @param inOffset
961   * @param length
962   */
963  public static void copyFromArrayToBuffer(ByteBuffer out, byte[] in, int inOffset, int length) {
964    if (out.hasArray()) {
965      System.arraycopy(in, inOffset, out.array(), out.arrayOffset() + out.position(), length);
966      // Move the position in out by length
967      out.position(out.position() + length);
968    } else if (UNSAFE_AVAIL) {
969      UnsafeAccess.copy(in, inOffset, out, out.position(), length);
970      // Move the position in out by length
971      out.position(out.position() + length);
972    } else {
973      out.put(in, inOffset, length);
974    }
975  }
976
977  /**
978   * Copies bytes from given array's offset to length part into the given buffer. Puts the bytes
979   * to buffer's given position. This doesn't affact the position of buffer.
980   * @param out
981   * @param in
982   * @param inOffset
983   * @param length
984   */
985  public static void copyFromArrayToBuffer(ByteBuffer out, int outOffset, byte[] in, int inOffset,
986      int length) {
987    if (out.hasArray()) {
988      System.arraycopy(in, inOffset, out.array(), out.arrayOffset() + outOffset, length);
989    } else if (UNSAFE_AVAIL) {
990      UnsafeAccess.copy(in, inOffset, out, outOffset, length);
991    } else {
992      ByteBuffer outDup = out.duplicate();
993      outDup.position(outOffset);
994      outDup.put(in, inOffset, length);
995    }
996  }
997
998  /**
999   * Copies specified number of bytes from given offset of 'in' ByteBuffer to
1000   * the array. This doesn't affact the position of buffer.
1001   * @param out
1002   * @param in
1003   * @param sourceOffset
1004   * @param destinationOffset
1005   * @param length
1006   */
1007  public static void copyFromBufferToArray(byte[] out, ByteBuffer in, int sourceOffset,
1008      int destinationOffset, int length) {
1009    if (in.hasArray()) {
1010      System.arraycopy(in.array(), sourceOffset + in.arrayOffset(), out, destinationOffset, length);
1011    } else if (UNSAFE_AVAIL) {
1012      UnsafeAccess.copy(in, sourceOffset, out, destinationOffset, length);
1013    } else {
1014      ByteBuffer inDup = in.duplicate();
1015      inDup.position(sourceOffset);
1016      inDup.get(out, destinationOffset, length);
1017    }
1018  }
1019
1020  /**
1021   * Similar to  {@link Arrays#copyOfRange(byte[], int, int)}
1022   * @param original the buffer from which the copy has to happen
1023   * @param from the starting index
1024   * @param to the ending index
1025   * @return a byte[] created out of the copy
1026   */
1027  public static byte[] copyOfRange(ByteBuffer original, int from, int to) {
1028    int newLength = to - from;
1029    if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
1030    byte[] copy = new byte[newLength];
1031    ByteBufferUtils.copyFromBufferToArray(copy, original, from, 0, newLength);
1032    return copy;
1033  }
1034
1035  // For testing purpose
1036  public static String toStringBinary(final ByteBuffer b, int off, int len) {
1037    StringBuilder result = new StringBuilder();
1038    // Just in case we are passed a 'len' that is > buffer length...
1039    if (off >= b.capacity())
1040      return result.toString();
1041    if (off + len > b.capacity())
1042      len = b.capacity() - off;
1043    for (int i = off; i < off + len; ++i) {
1044      int ch = b.get(i) & 0xFF;
1045      if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')
1046          || " `~!@#$%^&*()-_=+[]{}|;:'\",.<>/?".indexOf(ch) >= 0) {
1047        result.append((char) ch);
1048      } else {
1049        result.append(String.format("\\x%02X", ch));
1050      }
1051    }
1052    return result.toString();
1053  }
1054
1055  public static String toStringBinary(final ByteBuffer b) {
1056    return toStringBinary(b, 0, b.capacity());
1057  }
1058}