Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 1 | // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "src/string-builder.h" |
| 6 | |
| 7 | namespace v8 { |
| 8 | namespace internal { |
| 9 | |
| 10 | MaybeHandle<String> ReplacementStringBuilder::ToString() { |
| 11 | Isolate* isolate = heap_->isolate(); |
| 12 | if (array_builder_.length() == 0) { |
| 13 | return isolate->factory()->empty_string(); |
| 14 | } |
| 15 | |
| 16 | Handle<String> joined_string; |
| 17 | if (is_one_byte_) { |
| 18 | Handle<SeqOneByteString> seq; |
| 19 | ASSIGN_RETURN_ON_EXCEPTION( |
| 20 | isolate, seq, isolate->factory()->NewRawOneByteString(character_count_), |
| 21 | String); |
| 22 | |
| 23 | DisallowHeapAllocation no_gc; |
| 24 | uint8_t* char_buffer = seq->GetChars(); |
| 25 | StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(), |
| 26 | array_builder_.length()); |
| 27 | joined_string = Handle<String>::cast(seq); |
| 28 | } else { |
| 29 | // Two-byte. |
| 30 | Handle<SeqTwoByteString> seq; |
| 31 | ASSIGN_RETURN_ON_EXCEPTION( |
| 32 | isolate, seq, isolate->factory()->NewRawTwoByteString(character_count_), |
| 33 | String); |
| 34 | |
| 35 | DisallowHeapAllocation no_gc; |
| 36 | uc16* char_buffer = seq->GetChars(); |
| 37 | StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(), |
| 38 | array_builder_.length()); |
| 39 | joined_string = Handle<String>::cast(seq); |
| 40 | } |
| 41 | return joined_string; |
| 42 | } |
| 43 | |
| 44 | |
| 45 | IncrementalStringBuilder::IncrementalStringBuilder(Isolate* isolate) |
| 46 | : isolate_(isolate), |
| 47 | encoding_(String::ONE_BYTE_ENCODING), |
| 48 | overflowed_(false), |
| 49 | part_length_(kInitialPartLength), |
| 50 | current_index_(0) { |
| 51 | // Create an accumulator handle starting with the empty string. |
| 52 | accumulator_ = Handle<String>(isolate->heap()->empty_string(), isolate); |
| 53 | current_part_ = |
| 54 | factory()->NewRawOneByteString(part_length_).ToHandleChecked(); |
| 55 | } |
| 56 | |
| 57 | |
| 58 | void IncrementalStringBuilder::Accumulate() { |
| 59 | // Only accumulate fully written strings. Shrink first if necessary. |
| 60 | DCHECK_EQ(current_index_, current_part()->length()); |
| 61 | Handle<String> new_accumulator; |
| 62 | if (accumulator()->length() + current_part()->length() > String::kMaxLength) { |
| 63 | // Set the flag and carry on. Delay throwing the exception till the end. |
| 64 | new_accumulator = factory()->empty_string(); |
| 65 | overflowed_ = true; |
| 66 | } else { |
| 67 | new_accumulator = factory() |
| 68 | ->NewConsString(accumulator(), current_part()) |
| 69 | .ToHandleChecked(); |
| 70 | } |
| 71 | set_accumulator(new_accumulator); |
| 72 | } |
| 73 | |
| 74 | |
| 75 | void IncrementalStringBuilder::Extend() { |
| 76 | Accumulate(); |
| 77 | if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) { |
| 78 | part_length_ *= kPartLengthGrowthFactor; |
| 79 | } |
| 80 | Handle<String> new_part; |
| 81 | if (encoding_ == String::ONE_BYTE_ENCODING) { |
| 82 | new_part = factory()->NewRawOneByteString(part_length_).ToHandleChecked(); |
| 83 | } else { |
| 84 | new_part = factory()->NewRawTwoByteString(part_length_).ToHandleChecked(); |
| 85 | } |
| 86 | // Reuse the same handle to avoid being invalidated when exiting handle scope. |
| 87 | set_current_part(new_part); |
| 88 | current_index_ = 0; |
| 89 | } |
| 90 | |
| 91 | |
| 92 | MaybeHandle<String> IncrementalStringBuilder::Finish() { |
| 93 | ShrinkCurrentPart(); |
| 94 | Accumulate(); |
| 95 | if (overflowed_) { |
| 96 | THROW_NEW_ERROR(isolate_, NewInvalidStringLengthError(), String); |
| 97 | } |
| 98 | return accumulator(); |
| 99 | } |
| 100 | |
| 101 | |
| 102 | void IncrementalStringBuilder::AppendString(Handle<String> string) { |
| 103 | ShrinkCurrentPart(); |
| 104 | part_length_ = kInitialPartLength; // Allocate conservatively. |
| 105 | Extend(); // Attach current part and allocate new part. |
| 106 | Handle<String> concat = |
| 107 | factory()->NewConsString(accumulator(), string).ToHandleChecked(); |
| 108 | set_accumulator(concat); |
| 109 | } |
| 110 | } |
| 111 | } // namespace v8::internal |