| // Copyright 2014 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/string-builder.h" |
| |
| #include "src/isolate-inl.h" |
| #include "src/objects-inl.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| MaybeHandle<String> ReplacementStringBuilder::ToString() { |
| Isolate* isolate = heap_->isolate(); |
| if (array_builder_.length() == 0) { |
| return isolate->factory()->empty_string(); |
| } |
| |
| Handle<String> joined_string; |
| if (is_one_byte_) { |
| Handle<SeqOneByteString> seq; |
| ASSIGN_RETURN_ON_EXCEPTION( |
| isolate, seq, isolate->factory()->NewRawOneByteString(character_count_), |
| String); |
| |
| DisallowHeapAllocation no_gc; |
| uint8_t* char_buffer = seq->GetChars(); |
| StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(), |
| array_builder_.length()); |
| joined_string = Handle<String>::cast(seq); |
| } else { |
| // Two-byte. |
| Handle<SeqTwoByteString> seq; |
| ASSIGN_RETURN_ON_EXCEPTION( |
| isolate, seq, isolate->factory()->NewRawTwoByteString(character_count_), |
| String); |
| |
| DisallowHeapAllocation no_gc; |
| uc16* char_buffer = seq->GetChars(); |
| StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(), |
| array_builder_.length()); |
| joined_string = Handle<String>::cast(seq); |
| } |
| return joined_string; |
| } |
| |
| |
| IncrementalStringBuilder::IncrementalStringBuilder(Isolate* isolate) |
| : isolate_(isolate), |
| encoding_(String::ONE_BYTE_ENCODING), |
| overflowed_(false), |
| part_length_(kInitialPartLength), |
| current_index_(0) { |
| // Create an accumulator handle starting with the empty string. |
| accumulator_ = Handle<String>::New(isolate->heap()->empty_string(), isolate); |
| current_part_ = |
| factory()->NewRawOneByteString(part_length_).ToHandleChecked(); |
| } |
| |
| |
| void IncrementalStringBuilder::Accumulate(Handle<String> new_part) { |
| Handle<String> new_accumulator; |
| if (accumulator()->length() + new_part->length() > String::kMaxLength) { |
| // Set the flag and carry on. Delay throwing the exception till the end. |
| new_accumulator = factory()->empty_string(); |
| overflowed_ = true; |
| } else { |
| new_accumulator = |
| factory()->NewConsString(accumulator(), new_part).ToHandleChecked(); |
| } |
| set_accumulator(new_accumulator); |
| } |
| |
| |
| void IncrementalStringBuilder::Extend() { |
| DCHECK_EQ(current_index_, current_part()->length()); |
| Accumulate(current_part()); |
| if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) { |
| part_length_ *= kPartLengthGrowthFactor; |
| } |
| Handle<String> new_part; |
| if (encoding_ == String::ONE_BYTE_ENCODING) { |
| new_part = factory()->NewRawOneByteString(part_length_).ToHandleChecked(); |
| } else { |
| new_part = factory()->NewRawTwoByteString(part_length_).ToHandleChecked(); |
| } |
| // Reuse the same handle to avoid being invalidated when exiting handle scope. |
| set_current_part(new_part); |
| current_index_ = 0; |
| } |
| |
| |
| MaybeHandle<String> IncrementalStringBuilder::Finish() { |
| ShrinkCurrentPart(); |
| Accumulate(current_part()); |
| if (overflowed_) { |
| THROW_NEW_ERROR(isolate_, NewInvalidStringLengthError(), String); |
| } |
| return accumulator(); |
| } |
| |
| |
| void IncrementalStringBuilder::AppendString(Handle<String> string) { |
| ShrinkCurrentPart(); |
| part_length_ = kInitialPartLength; // Allocate conservatively. |
| Extend(); // Attach current part and allocate new part. |
| Accumulate(string); |
| } |
| } // namespace internal |
| } // namespace v8 |