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