1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import java.io.ByteArrayInputStream; 34 import java.io.IOException; 35 import java.io.InputStream; 36 import java.io.InvalidObjectException; 37 import java.io.ObjectInputStream; 38 import java.io.OutputStream; 39 import java.nio.ByteBuffer; 40 import java.nio.charset.Charset; 41 import java.util.ArrayList; 42 import java.util.Arrays; 43 import java.util.Iterator; 44 import java.util.List; 45 import java.util.NoSuchElementException; 46 import java.util.Stack; 47 48 /** 49 * Class to represent {@code ByteStrings} formed by concatenation of other 50 * ByteStrings, without copying the data in the pieces. The concatenation is 51 * represented as a tree whose leaf nodes are each a 52 * {@link com.google.protobuf.ByteString.LeafByteString}. 53 * 54 * <p>Most of the operation here is inspired by the now-famous paper <a 55 * href="https://web.archive.org/web/20060202015456/http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf"> 56 * BAP95 </a> Ropes: an Alternative to Strings hans-j. boehm, russ atkinson and 57 * michael plass 58 * 59 * <p>The algorithms described in the paper have been implemented for character 60 * strings in {@code com.google.common.string.Rope} and in the c++ class {@code 61 * cord.cc}. 62 * 63 * <p>Fundamentally the Rope algorithm represents the collection of pieces as a 64 * binary tree. BAP95 uses a Fibonacci bound relating depth to a minimum 65 * sequence length, sequences that are too short relative to their depth cause a 66 * tree rebalance. More precisely, a tree of depth d is "balanced" in the 67 * terminology of BAP95 if its length is at least F(d+2), where F(n) is the 68 * n-the Fibonacci number. Thus for depths 0, 1, 2, 3, 4, 5,... we have minimum 69 * lengths 1, 2, 3, 5, 8, 13,... 70 * 71 * @author carlanton@google.com (Carl Haverl) 72 */ 73 final class RopeByteString extends ByteString { 74 75 /** 76 * BAP95. Let Fn be the nth Fibonacci number. A {@link RopeByteString} of 77 * depth n is "balanced", i.e flat enough, if its length is at least Fn+2, 78 * e.g. a "balanced" {@link RopeByteString} of depth 1 must have length at 79 * least 2, of depth 4 must have length >= 8, etc. 80 * 81 * <p>There's nothing special about using the Fibonacci numbers for this, but 82 * they are a reasonable sequence for encapsulating the idea that we are OK 83 * with longer strings being encoded in deeper binary trees. 84 * 85 * <p>For 32-bit integers, this array has length 46. 86 */ 87 private static final int[] minLengthByDepth; 88 89 static { 90 // Dynamically generate the list of Fibonacci numbers the first time this 91 // class is accessed. 92 List<Integer> numbers = new ArrayList<Integer>(); 93 94 // we skip the first Fibonacci number (1). So instead of: 1 1 2 3 5 8 ... 95 // we have: 1 2 3 5 8 ... 96 int f1 = 1; 97 int f2 = 1; 98 99 // get all the values until we roll over. 100 while (f2 > 0) { 101 numbers.add(f2); 102 int temp = f1 + f2; 103 f1 = f2; 104 f2 = temp; 105 } 106 107 // we include this here so that we can index this array to [x + 1] in the 108 // loops below. 109 numbers.add(Integer.MAX_VALUE); 110 minLengthByDepth = new int[numbers.size()]; 111 for (int i = 0; i < minLengthByDepth.length; i++) { 112 // unbox all the values 113 minLengthByDepth[i] = numbers.get(i); 114 } 115 } 116 117 private final int totalLength; 118 private final ByteString left; 119 private final ByteString right; 120 private final int leftLength; 121 private final int treeDepth; 122 123 /** 124 * Create a new RopeByteString, which can be thought of as a new tree node, by 125 * recording references to the two given strings. 126 * 127 * @param left string on the left of this node, should have {@code size() > 128 * 0} 129 * @param right string on the right of this node, should have {@code size() > 130 * 0} 131 */ RopeByteString(ByteString left, ByteString right)132 private RopeByteString(ByteString left, ByteString right) { 133 this.left = left; 134 this.right = right; 135 leftLength = left.size(); 136 totalLength = leftLength + right.size(); 137 treeDepth = Math.max(left.getTreeDepth(), right.getTreeDepth()) + 1; 138 } 139 140 /** 141 * Concatenate the given strings while performing various optimizations to 142 * slow the growth rate of tree depth and tree node count. The result is 143 * either a {@link com.google.protobuf.ByteString.LeafByteString} or a 144 * {@link RopeByteString} depending on which optimizations, if any, were 145 * applied. 146 * 147 * <p>Small pieces of length less than {@link 148 * ByteString#CONCATENATE_BY_COPY_SIZE} may be copied by value here, as in 149 * BAP95. Large pieces are referenced without copy. 150 * 151 * @param left string on the left 152 * @param right string on the right 153 * @return concatenation representing the same sequence as the given strings 154 */ concatenate(ByteString left, ByteString right)155 static ByteString concatenate(ByteString left, ByteString right) { 156 if (right.size() == 0) { 157 return left; 158 } 159 160 if (left.size() == 0) { 161 return right; 162 } 163 164 final int newLength = left.size() + right.size(); 165 if (newLength < ByteString.CONCATENATE_BY_COPY_SIZE) { 166 // Optimization from BAP95: For short (leaves in paper, but just short 167 // here) total length, do a copy of data to a new leaf. 168 return concatenateBytes(left, right); 169 } 170 171 if (left instanceof RopeByteString) { 172 final RopeByteString leftRope = (RopeByteString) left; 173 if (leftRope.right.size() + right.size() < CONCATENATE_BY_COPY_SIZE) { 174 // Optimization from BAP95: As an optimization of the case where the 175 // ByteString is constructed by repeated concatenate, recognize the case 176 // where a short string is concatenated to a left-hand node whose 177 // right-hand branch is short. In the paper this applies to leaves, but 178 // we just look at the length here. This has the advantage of shedding 179 // references to unneeded data when substrings have been taken. 180 // 181 // When we recognize this case, we do a copy of the data and create a 182 // new parent node so that the depth of the result is the same as the 183 // given left tree. 184 ByteString newRight = concatenateBytes(leftRope.right, right); 185 return new RopeByteString(leftRope.left, newRight); 186 } 187 188 if (leftRope.left.getTreeDepth() > leftRope.right.getTreeDepth() 189 && leftRope.getTreeDepth() > right.getTreeDepth()) { 190 // Typically for concatenate-built strings the left-side is deeper than 191 // the right. This is our final attempt to concatenate without 192 // increasing the tree depth. We'll redo the node on the RHS. This 193 // is yet another optimization for building the string by repeatedly 194 // concatenating on the right. 195 ByteString newRight = new RopeByteString(leftRope.right, right); 196 return new RopeByteString(leftRope.left, newRight); 197 } 198 } 199 200 // Fine, we'll add a node and increase the tree depth--unless we rebalance ;^) 201 int newDepth = Math.max(left.getTreeDepth(), right.getTreeDepth()) + 1; 202 if (newLength >= minLengthByDepth[newDepth]) { 203 // The tree is shallow enough, so don't rebalance 204 return new RopeByteString(left, right); 205 } 206 207 return new Balancer().balance(left, right); 208 } 209 210 /** 211 * Concatenates two strings by copying data values. This is called in a few 212 * cases in order to reduce the growth of the number of tree nodes. 213 * 214 * @param left string on the left 215 * @param right string on the right 216 * @return string formed by copying data bytes 217 */ concatenateBytes(ByteString left, ByteString right)218 private static ByteString concatenateBytes(ByteString left, 219 ByteString right) { 220 int leftSize = left.size(); 221 int rightSize = right.size(); 222 byte[] bytes = new byte[leftSize + rightSize]; 223 left.copyTo(bytes, 0, 0, leftSize); 224 right.copyTo(bytes, 0, leftSize, rightSize); 225 return ByteString.wrap(bytes); // Constructor wraps bytes 226 } 227 228 /** 229 * Create a new RopeByteString for testing only while bypassing all the 230 * defenses of {@link #concatenate(ByteString, ByteString)}. This allows 231 * testing trees of specific structure. We are also able to insert empty 232 * leaves, though these are dis-allowed, so that we can make sure the 233 * implementation can withstand their presence. 234 * 235 * @param left string on the left of this node 236 * @param right string on the right of this node 237 * @return an unsafe instance for testing only 238 */ newInstanceForTest(ByteString left, ByteString right)239 static RopeByteString newInstanceForTest(ByteString left, ByteString right) { 240 return new RopeByteString(left, right); 241 } 242 243 /** 244 * Gets the byte at the given index. 245 * Throws {@link ArrayIndexOutOfBoundsException} for backwards-compatibility 246 * reasons although it would more properly be {@link 247 * IndexOutOfBoundsException}. 248 * 249 * @param index index of byte 250 * @return the value 251 * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size 252 */ 253 @Override byteAt(int index)254 public byte byteAt(int index) { 255 checkIndex(index, totalLength); 256 257 // Find the relevant piece by recursive descent 258 if (index < leftLength) { 259 return left.byteAt(index); 260 } 261 262 return right.byteAt(index - leftLength); 263 } 264 265 @Override size()266 public int size() { 267 return totalLength; 268 } 269 270 // ================================================================= 271 // Pieces 272 273 @Override getTreeDepth()274 protected int getTreeDepth() { 275 return treeDepth; 276 } 277 278 /** 279 * Determines if the tree is balanced according to BAP95, which means the tree 280 * is flat-enough with respect to the bounds. Note that this definition of 281 * balanced is one where sub-trees of balanced trees are not necessarily 282 * balanced. 283 * 284 * @return true if the tree is balanced 285 */ 286 @Override isBalanced()287 protected boolean isBalanced() { 288 return totalLength >= minLengthByDepth[treeDepth]; 289 } 290 291 /** 292 * Takes a substring of this one. This involves recursive descent along the 293 * left and right edges of the substring, and referencing any wholly contained 294 * segments in between. Any leaf nodes entirely uninvolved in the substring 295 * will not be referenced by the substring. 296 * 297 * <p>Substrings of {@code length < 2} should result in at most a single 298 * recursive call chain, terminating at a leaf node. Thus the result will be a 299 * {@link com.google.protobuf.ByteString.LeafByteString}. 300 * 301 * @param beginIndex start at this index 302 * @param endIndex the last character is the one before this index 303 * @return substring leaf node or tree 304 */ 305 @Override substring(int beginIndex, int endIndex)306 public ByteString substring(int beginIndex, int endIndex) { 307 final int length = checkRange(beginIndex, endIndex, totalLength); 308 309 if (length == 0) { 310 // Empty substring 311 return ByteString.EMPTY; 312 } 313 314 if (length == totalLength) { 315 // The whole string 316 return this; 317 } 318 319 // Proper substring 320 if (endIndex <= leftLength) { 321 // Substring on the left 322 return left.substring(beginIndex, endIndex); 323 } 324 325 if (beginIndex >= leftLength) { 326 // Substring on the right 327 return right.substring(beginIndex - leftLength, endIndex - leftLength); 328 } 329 330 // Split substring 331 ByteString leftSub = left.substring(beginIndex); 332 ByteString rightSub = right.substring(0, endIndex - leftLength); 333 // Intentionally not rebalancing, since in many cases these two 334 // substrings will already be less deep than the top-level 335 // RopeByteString we're taking a substring of. 336 return new RopeByteString(leftSub, rightSub); 337 } 338 339 // ================================================================= 340 // ByteString -> byte[] 341 342 @Override copyToInternal(byte[] target, int sourceOffset, int targetOffset, int numberToCopy)343 protected void copyToInternal(byte[] target, int sourceOffset, 344 int targetOffset, int numberToCopy) { 345 if (sourceOffset + numberToCopy <= leftLength) { 346 left.copyToInternal(target, sourceOffset, targetOffset, numberToCopy); 347 } else if (sourceOffset >= leftLength) { 348 right.copyToInternal(target, sourceOffset - leftLength, targetOffset, 349 numberToCopy); 350 } else { 351 int leftLength = this.leftLength - sourceOffset; 352 left.copyToInternal(target, sourceOffset, targetOffset, leftLength); 353 right.copyToInternal(target, 0, targetOffset + leftLength, 354 numberToCopy - leftLength); 355 } 356 } 357 358 @Override copyTo(ByteBuffer target)359 public void copyTo(ByteBuffer target) { 360 left.copyTo(target); 361 right.copyTo(target); 362 } 363 364 @Override asReadOnlyByteBuffer()365 public ByteBuffer asReadOnlyByteBuffer() { 366 ByteBuffer byteBuffer = ByteBuffer.wrap(toByteArray()); 367 return byteBuffer.asReadOnlyBuffer(); 368 } 369 370 @Override asReadOnlyByteBufferList()371 public List<ByteBuffer> asReadOnlyByteBufferList() { 372 // Walk through the list of LeafByteString's that make up this 373 // rope, and add each one as a read-only ByteBuffer. 374 List<ByteBuffer> result = new ArrayList<ByteBuffer>(); 375 PieceIterator pieces = new PieceIterator(this); 376 while (pieces.hasNext()) { 377 LeafByteString byteString = pieces.next(); 378 result.add(byteString.asReadOnlyByteBuffer()); 379 } 380 return result; 381 } 382 383 @Override writeTo(OutputStream outputStream)384 public void writeTo(OutputStream outputStream) throws IOException { 385 left.writeTo(outputStream); 386 right.writeTo(outputStream); 387 } 388 389 @Override writeToInternal(OutputStream out, int sourceOffset, int numberToWrite)390 void writeToInternal(OutputStream out, int sourceOffset, 391 int numberToWrite) throws IOException { 392 if (sourceOffset + numberToWrite <= leftLength) { 393 left.writeToInternal(out, sourceOffset, numberToWrite); 394 } else if (sourceOffset >= leftLength) { 395 right.writeToInternal(out, sourceOffset - leftLength, numberToWrite); 396 } else { 397 int numberToWriteInLeft = leftLength - sourceOffset; 398 left.writeToInternal(out, sourceOffset, numberToWriteInLeft); 399 right.writeToInternal(out, 0, numberToWrite - numberToWriteInLeft); 400 } 401 } 402 403 @Override writeTo(ByteOutput output)404 void writeTo(ByteOutput output) throws IOException { 405 left.writeTo(output); 406 right.writeTo(output); 407 } 408 409 @Override toStringInternal(Charset charset)410 protected String toStringInternal(Charset charset) { 411 return new String(toByteArray(), charset); 412 } 413 414 // ================================================================= 415 // UTF-8 decoding 416 417 @Override isValidUtf8()418 public boolean isValidUtf8() { 419 int leftPartial = left.partialIsValidUtf8(Utf8.COMPLETE, 0, leftLength); 420 int state = right.partialIsValidUtf8(leftPartial, 0, right.size()); 421 return state == Utf8.COMPLETE; 422 } 423 424 @Override partialIsValidUtf8(int state, int offset, int length)425 protected int partialIsValidUtf8(int state, int offset, int length) { 426 int toIndex = offset + length; 427 if (toIndex <= leftLength) { 428 return left.partialIsValidUtf8(state, offset, length); 429 } else if (offset >= leftLength) { 430 return right.partialIsValidUtf8(state, offset - leftLength, length); 431 } else { 432 int leftLength = this.leftLength - offset; 433 int leftPartial = left.partialIsValidUtf8(state, offset, leftLength); 434 return right.partialIsValidUtf8(leftPartial, 0, length - leftLength); 435 } 436 } 437 438 // ================================================================= 439 // equals() and hashCode() 440 441 @Override equals(Object other)442 public boolean equals(Object other) { 443 if (other == this) { 444 return true; 445 } 446 if (!(other instanceof ByteString)) { 447 return false; 448 } 449 450 ByteString otherByteString = (ByteString) other; 451 if (totalLength != otherByteString.size()) { 452 return false; 453 } 454 if (totalLength == 0) { 455 return true; 456 } 457 458 // You don't really want to be calling equals on long strings, but since 459 // we cache the hashCode, we effectively cache inequality. We use the cached 460 // hashCode if it's already computed. It's arguable we should compute the 461 // hashCode here, and if we're going to be testing a bunch of byteStrings, 462 // it might even make sense. 463 int thisHash = peekCachedHashCode(); 464 int thatHash = otherByteString.peekCachedHashCode(); 465 if (thisHash != 0 && thatHash != 0 && thisHash != thatHash) { 466 return false; 467 } 468 469 return equalsFragments(otherByteString); 470 } 471 472 /** 473 * Determines if this string is equal to another of the same length by 474 * iterating over the leaf nodes. On each step of the iteration, the 475 * overlapping segments of the leaves are compared. 476 * 477 * @param other string of the same length as this one 478 * @return true if the values of this string equals the value of the given 479 * one 480 */ equalsFragments(ByteString other)481 private boolean equalsFragments(ByteString other) { 482 int thisOffset = 0; 483 Iterator<LeafByteString> thisIter = new PieceIterator(this); 484 LeafByteString thisString = thisIter.next(); 485 486 int thatOffset = 0; 487 Iterator<LeafByteString> thatIter = new PieceIterator(other); 488 LeafByteString thatString = thatIter.next(); 489 490 int pos = 0; 491 while (true) { 492 int thisRemaining = thisString.size() - thisOffset; 493 int thatRemaining = thatString.size() - thatOffset; 494 int bytesToCompare = Math.min(thisRemaining, thatRemaining); 495 496 // At least one of the offsets will be zero 497 boolean stillEqual = (thisOffset == 0) 498 ? thisString.equalsRange(thatString, thatOffset, bytesToCompare) 499 : thatString.equalsRange(thisString, thisOffset, bytesToCompare); 500 if (!stillEqual) { 501 return false; 502 } 503 504 pos += bytesToCompare; 505 if (pos >= totalLength) { 506 if (pos == totalLength) { 507 return true; 508 } 509 throw new IllegalStateException(); 510 } 511 // We always get to the end of at least one of the pieces 512 if (bytesToCompare == thisRemaining) { // If reached end of this 513 thisOffset = 0; 514 thisString = thisIter.next(); 515 } else { 516 thisOffset += bytesToCompare; 517 } 518 if (bytesToCompare == thatRemaining) { // If reached end of that 519 thatOffset = 0; 520 thatString = thatIter.next(); 521 } else { 522 thatOffset += bytesToCompare; 523 } 524 } 525 } 526 527 @Override partialHash(int h, int offset, int length)528 protected int partialHash(int h, int offset, int length) { 529 int toIndex = offset + length; 530 if (toIndex <= leftLength) { 531 return left.partialHash(h, offset, length); 532 } else if (offset >= leftLength) { 533 return right.partialHash(h, offset - leftLength, length); 534 } else { 535 int leftLength = this.leftLength - offset; 536 int leftPartial = left.partialHash(h, offset, leftLength); 537 return right.partialHash(leftPartial, 0, length - leftLength); 538 } 539 } 540 541 // ================================================================= 542 // Input stream 543 544 @Override newCodedInput()545 public CodedInputStream newCodedInput() { 546 return CodedInputStream.newInstance(new RopeInputStream()); 547 } 548 549 @Override newInput()550 public InputStream newInput() { 551 return new RopeInputStream(); 552 } 553 554 /** 555 * This class implements the balancing algorithm of BAP95. In the paper the 556 * authors use an array to keep track of pieces, while here we use a stack. 557 * The tree is balanced by traversing subtrees in left to right order, and the 558 * stack always contains the part of the string we've traversed so far. 559 * 560 * <p>One surprising aspect of the algorithm is the result of balancing is not 561 * necessarily balanced, though it is nearly balanced. For details, see 562 * BAP95. 563 */ 564 private static class Balancer { 565 // Stack containing the part of the string, starting from the left, that 566 // we've already traversed. The final string should be the equivalent of 567 // concatenating the strings on the stack from bottom to top. 568 private final Stack<ByteString> prefixesStack = new Stack<ByteString>(); 569 balance(ByteString left, ByteString right)570 private ByteString balance(ByteString left, ByteString right) { 571 doBalance(left); 572 doBalance(right); 573 574 // Sweep stack to gather the result 575 ByteString partialString = prefixesStack.pop(); 576 while (!prefixesStack.isEmpty()) { 577 ByteString newLeft = prefixesStack.pop(); 578 partialString = new RopeByteString(newLeft, partialString); 579 } 580 // We should end up with a RopeByteString since at a minimum we will 581 // create one from concatenating left and right 582 return partialString; 583 } 584 doBalance(ByteString root)585 private void doBalance(ByteString root) { 586 // BAP95: Insert balanced subtrees whole. This means the result might not 587 // be balanced, leading to repeated rebalancings on concatenate. However, 588 // these rebalancings are shallow due to ignoring balanced subtrees, and 589 // relatively few calls to insert() result. 590 if (root.isBalanced()) { 591 insert(root); 592 } else if (root instanceof RopeByteString) { 593 RopeByteString rbs = (RopeByteString) root; 594 doBalance(rbs.left); 595 doBalance(rbs.right); 596 } else { 597 throw new IllegalArgumentException( 598 "Has a new type of ByteString been created? Found " + 599 root.getClass()); 600 } 601 } 602 603 /** 604 * Push a string on the balance stack (BAP95). BAP95 uses an array and 605 * calls the elements in the array 'bins'. We instead use a stack, so the 606 * 'bins' of lengths are represented by differences between the elements of 607 * minLengthByDepth. 608 * 609 * <p>If the length bin for our string, and all shorter length bins, are 610 * empty, we just push it on the stack. Otherwise, we need to start 611 * concatenating, putting the given string in the "middle" and continuing 612 * until we land in an empty length bin that matches the length of our 613 * concatenation. 614 * 615 * @param byteString string to place on the balance stack 616 */ insert(ByteString byteString)617 private void insert(ByteString byteString) { 618 int depthBin = getDepthBinForLength(byteString.size()); 619 int binEnd = minLengthByDepth[depthBin + 1]; 620 621 // BAP95: Concatenate all trees occupying bins representing the length of 622 // our new piece or of shorter pieces, to the extent that is possible. 623 // The goal is to clear the bin which our piece belongs in, but that may 624 // not be entirely possible if there aren't enough longer bins occupied. 625 if (prefixesStack.isEmpty() || prefixesStack.peek().size() >= binEnd) { 626 prefixesStack.push(byteString); 627 } else { 628 int binStart = minLengthByDepth[depthBin]; 629 630 // Concatenate the subtrees of shorter length 631 ByteString newTree = prefixesStack.pop(); 632 while (!prefixesStack.isEmpty() 633 && prefixesStack.peek().size() < binStart) { 634 ByteString left = prefixesStack.pop(); 635 newTree = new RopeByteString(left, newTree); 636 } 637 638 // Concatenate the given string 639 newTree = new RopeByteString(newTree, byteString); 640 641 // Continue concatenating until we land in an empty bin 642 while (!prefixesStack.isEmpty()) { 643 depthBin = getDepthBinForLength(newTree.size()); 644 binEnd = minLengthByDepth[depthBin + 1]; 645 if (prefixesStack.peek().size() < binEnd) { 646 ByteString left = prefixesStack.pop(); 647 newTree = new RopeByteString(left, newTree); 648 } else { 649 break; 650 } 651 } 652 prefixesStack.push(newTree); 653 } 654 } 655 getDepthBinForLength(int length)656 private int getDepthBinForLength(int length) { 657 int depth = Arrays.binarySearch(minLengthByDepth, length); 658 if (depth < 0) { 659 // It wasn't an exact match, so convert to the index of the containing 660 // fragment, which is one less even than the insertion point. 661 int insertionPoint = -(depth + 1); 662 depth = insertionPoint - 1; 663 } 664 665 return depth; 666 } 667 } 668 669 /** 670 * This class is a continuable tree traversal, which keeps the state 671 * information which would exist on the stack in a recursive traversal instead 672 * on a stack of "Bread Crumbs". The maximum depth of the stack in this 673 * iterator is the same as the depth of the tree being traversed. 674 * 675 * <p>This iterator is used to implement 676 * {@link RopeByteString#equalsFragments(ByteString)}. 677 */ 678 private static class PieceIterator implements Iterator<LeafByteString> { 679 680 private final Stack<RopeByteString> breadCrumbs = 681 new Stack<RopeByteString>(); 682 private LeafByteString next; 683 PieceIterator(ByteString root)684 private PieceIterator(ByteString root) { 685 next = getLeafByLeft(root); 686 } 687 getLeafByLeft(ByteString root)688 private LeafByteString getLeafByLeft(ByteString root) { 689 ByteString pos = root; 690 while (pos instanceof RopeByteString) { 691 RopeByteString rbs = (RopeByteString) pos; 692 breadCrumbs.push(rbs); 693 pos = rbs.left; 694 } 695 return (LeafByteString) pos; 696 } 697 getNextNonEmptyLeaf()698 private LeafByteString getNextNonEmptyLeaf() { 699 while (true) { 700 // Almost always, we go through this loop exactly once. However, if 701 // we discover an empty string in the rope, we toss it and try again. 702 if (breadCrumbs.isEmpty()) { 703 return null; 704 } else { 705 LeafByteString result = getLeafByLeft(breadCrumbs.pop().right); 706 if (!result.isEmpty()) { 707 return result; 708 } 709 } 710 } 711 } 712 713 @Override hasNext()714 public boolean hasNext() { 715 return next != null; 716 } 717 718 /** 719 * Returns the next item and advances one 720 * {@link com.google.protobuf.ByteString.LeafByteString}. 721 * 722 * @return next non-empty LeafByteString or {@code null} 723 */ 724 @Override next()725 public LeafByteString next() { 726 if (next == null) { 727 throw new NoSuchElementException(); 728 } 729 LeafByteString result = next; 730 next = getNextNonEmptyLeaf(); 731 return result; 732 } 733 734 @Override remove()735 public void remove() { 736 throw new UnsupportedOperationException(); 737 } 738 } 739 740 // ================================================================= 741 // Serializable 742 743 private static final long serialVersionUID = 1L; 744 writeReplace()745 Object writeReplace() { 746 return ByteString.wrap(toByteArray()); 747 } 748 readObject(@uppressWarnings"unused") ObjectInputStream in)749 private void readObject(@SuppressWarnings("unused") ObjectInputStream in) throws IOException { 750 throw new InvalidObjectException( 751 "RopeByteStream instances are not to be serialized directly"); 752 } 753 754 /** 755 * This class is the {@link RopeByteString} equivalent for 756 * {@link ByteArrayInputStream}. 757 */ 758 private class RopeInputStream extends InputStream { 759 // Iterates through the pieces of the rope 760 private PieceIterator pieceIterator; 761 // The current piece 762 private LeafByteString currentPiece; 763 // The size of the current piece 764 private int currentPieceSize; 765 // The index of the next byte to read in the current piece 766 private int currentPieceIndex; 767 // The offset of the start of the current piece in the rope byte string 768 private int currentPieceOffsetInRope; 769 // Offset in the buffer at which user called mark(); 770 private int mark; 771 RopeInputStream()772 public RopeInputStream() { 773 initialize(); 774 } 775 776 @Override read(byte b[], int offset, int length)777 public int read(byte b[], int offset, int length) { 778 if (b == null) { 779 throw new NullPointerException(); 780 } else if (offset < 0 || length < 0 || length > b.length - offset) { 781 throw new IndexOutOfBoundsException(); 782 } 783 return readSkipInternal(b, offset, length); 784 } 785 786 @Override skip(long length)787 public long skip(long length) { 788 if (length < 0) { 789 throw new IndexOutOfBoundsException(); 790 } else if (length > Integer.MAX_VALUE) { 791 length = Integer.MAX_VALUE; 792 } 793 return readSkipInternal(null, 0, (int) length); 794 } 795 796 /** 797 * Internal implementation of read and skip. If b != null, then read the 798 * next {@code length} bytes into the buffer {@code b} at 799 * offset {@code offset}. If b == null, then skip the next {@code length} 800 * bytes. 801 * <p> 802 * This method assumes that all error checking has already happened. 803 * <p> 804 * Returns the actual number of bytes read or skipped. 805 */ readSkipInternal(byte b[], int offset, int length)806 private int readSkipInternal(byte b[], int offset, int length) { 807 int bytesRemaining = length; 808 while (bytesRemaining > 0) { 809 advanceIfCurrentPieceFullyRead(); 810 if (currentPiece == null) { 811 if (bytesRemaining == length) { 812 // We didn't manage to read anything 813 return -1; 814 } 815 break; 816 } else { 817 // Copy the bytes from this piece. 818 int currentPieceRemaining = currentPieceSize - currentPieceIndex; 819 int count = Math.min(currentPieceRemaining, bytesRemaining); 820 if (b != null) { 821 currentPiece.copyTo(b, currentPieceIndex, offset, count); 822 offset += count; 823 } 824 currentPieceIndex += count; 825 bytesRemaining -= count; 826 } 827 } 828 // Return the number of bytes read. 829 return length - bytesRemaining; 830 } 831 832 @Override read()833 public int read() throws IOException { 834 advanceIfCurrentPieceFullyRead(); 835 if (currentPiece == null) { 836 return -1; 837 } else { 838 return currentPiece.byteAt(currentPieceIndex++) & 0xFF; 839 } 840 } 841 842 @Override available()843 public int available() throws IOException { 844 int bytesRead = currentPieceOffsetInRope + currentPieceIndex; 845 return RopeByteString.this.size() - bytesRead; 846 } 847 848 @Override markSupported()849 public boolean markSupported() { 850 return true; 851 } 852 853 @Override mark(int readAheadLimit)854 public void mark(int readAheadLimit) { 855 // Set the mark to our position in the byte string 856 mark = currentPieceOffsetInRope + currentPieceIndex; 857 } 858 859 @Override reset()860 public synchronized void reset() { 861 // Just reinitialize and skip the specified number of bytes. 862 initialize(); 863 readSkipInternal(null, 0, mark); 864 } 865 866 /** Common initialization code used by both the constructor and reset() */ initialize()867 private void initialize() { 868 pieceIterator = new PieceIterator(RopeByteString.this); 869 currentPiece = pieceIterator.next(); 870 currentPieceSize = currentPiece.size(); 871 currentPieceIndex = 0; 872 currentPieceOffsetInRope = 0; 873 } 874 875 /** 876 * Skips to the next piece if we have read all the data in the current 877 * piece. Sets currentPiece to null if we have reached the end of the 878 * input. 879 */ advanceIfCurrentPieceFullyRead()880 private void advanceIfCurrentPieceFullyRead() { 881 if (currentPiece != null && currentPieceIndex == currentPieceSize) { 882 // Generally, we can only go through this loop at most once, since 883 // empty strings can't end up in a rope. But better to test. 884 currentPieceOffsetInRope += currentPieceSize; 885 currentPieceIndex = 0; 886 if (pieceIterator.hasNext()) { 887 currentPiece = pieceIterator.next(); 888 currentPieceSize = currentPiece.size(); 889 } else { 890 currentPiece = null; 891 currentPieceSize = 0; 892 } 893 } 894 } 895 } 896 } 897