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}