%PDF- %PDF-
Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/strings/ |
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/strings/string-builder-inl.h |
// 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. #ifndef V8_STRINGS_STRING_BUILDER_INL_H_ #define V8_STRINGS_STRING_BUILDER_INL_H_ #include "src/common/assert-scope.h" #include "src/execution/isolate.h" #include "src/handles/handles-inl.h" #include "src/heap/factory.h" #include "src/objects/fixed-array.h" #include "src/objects/objects.h" #include "src/objects/string-inl.h" namespace v8 { namespace internal { const int kStringBuilderConcatHelperLengthBits = 11; const int kStringBuilderConcatHelperPositionBits = 19; using StringBuilderSubstringLength = base::BitField<int, 0, kStringBuilderConcatHelperLengthBits>; using StringBuilderSubstringPosition = base::BitField<int, kStringBuilderConcatHelperLengthBits, kStringBuilderConcatHelperPositionBits>; template <typename sinkchar> void StringBuilderConcatHelper(Tagged<String> special, sinkchar* sink, Tagged<FixedArray> fixed_array, int array_length); // Returns the result length of the concatenation. // On illegal argument, -1 is returned. int StringBuilderConcatLength(int special_length, Tagged<FixedArray> fixed_array, int array_length, bool* one_byte); class FixedArrayBuilder { public: explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity); explicit FixedArrayBuilder(Handle<FixedArray> backing_store); // Creates a FixedArrayBuilder which allocates its backing store lazily when // EnsureCapacity is called. static FixedArrayBuilder Lazy(Isolate* isolate); bool HasCapacity(int elements); void EnsureCapacity(Isolate* isolate, int elements); void Add(Tagged<Object> value); void Add(Tagged<Smi> value); Handle<FixedArray> array() { return array_; } int length() { return length_; } int capacity(); private: explicit FixedArrayBuilder(Isolate* isolate); Handle<FixedArray> array_; int length_; bool has_non_smi_elements_; }; class ReplacementStringBuilder { public: ReplacementStringBuilder(Heap* heap, Handle<String> subject, int estimated_part_count); // Caution: Callers must ensure the builder has enough capacity. static inline void AddSubjectSlice(FixedArrayBuilder* builder, int from, int to) { DCHECK_GE(from, 0); int length = to - from; DCHECK_GT(length, 0); if (StringBuilderSubstringLength::is_valid(length) && StringBuilderSubstringPosition::is_valid(from)) { int encoded_slice = StringBuilderSubstringLength::encode(length) | StringBuilderSubstringPosition::encode(from); builder->Add(Smi::FromInt(encoded_slice)); } else { // Otherwise encode as two smis. builder->Add(Smi::FromInt(-length)); builder->Add(Smi::FromInt(from)); } } void AddSubjectSlice(int from, int to) { EnsureCapacity(2); // Subject slices are encoded with up to two smis. AddSubjectSlice(&array_builder_, from, to); IncrementCharacterCount(to - from); } void AddString(Handle<String> string); MaybeHandle<String> ToString(); void IncrementCharacterCount(int by) { if (character_count_ > String::kMaxLength - by) { static_assert(String::kMaxLength < kMaxInt); character_count_ = kMaxInt; } else { character_count_ += by; } } private: void AddElement(Handle<Object> element); void EnsureCapacity(int elements); Heap* heap_; FixedArrayBuilder array_builder_; Handle<String> subject_; int character_count_; bool is_one_byte_; }; class IncrementalStringBuilder { public: explicit IncrementalStringBuilder(Isolate* isolate); V8_INLINE String::Encoding CurrentEncoding() { return encoding_; } template <typename SrcChar, typename DestChar> V8_INLINE void Append(SrcChar c); V8_INLINE void AppendCharacter(uint8_t c) { if (encoding_ == String::ONE_BYTE_ENCODING) { Append<uint8_t, uint8_t>(c); } else { Append<uint8_t, base::uc16>(c); } } template <int N> V8_INLINE void AppendCStringLiteral(const char (&literal)[N]) { // Note that the literal contains the zero char. const int length = N - 1; static_assert(length > 0); if (length == 1) return AppendCharacter(literal[0]); if (encoding_ == String::ONE_BYTE_ENCODING && CurrentPartCanFit(N)) { const uint8_t* chars = reinterpret_cast<const uint8_t*>(literal); SeqOneByteString::cast(*current_part_) ->SeqOneByteStringSetChars(current_index_, chars, length); current_index_ += length; if (current_index_ == part_length_) Extend(); DCHECK(HasValidCurrentIndex()); return; } return AppendCString(literal); } template <typename SrcChar> V8_INLINE void AppendCString(const SrcChar* s) { if (encoding_ == String::ONE_BYTE_ENCODING) { while (*s != '\0') Append<SrcChar, uint8_t>(*s++); } else { while (*s != '\0') Append<SrcChar, base::uc16>(*s++); } } V8_INLINE void AppendInt(int i) { char buffer[kIntToCStringBufferSize]; const char* str = IntToCString(i, base::Vector<char>(buffer, kIntToCStringBufferSize)); AppendCString(str); } V8_INLINE bool CurrentPartCanFit(int length) { return part_length_ - current_index_ > length; } // We make a rough estimate to find out if the current string can be // serialized without allocating a new string part. The worst case length of // an escaped character is 6. Shifting the remaining string length right by 3 // is a more pessimistic estimate, but faster to calculate. V8_INLINE int EscapedLengthIfCurrentPartFits(int length) { if (length > kMaxPartLength) return 0; static_assert((kMaxPartLength << 3) <= String::kMaxLength); // This shift will not overflow because length is already less than the // maximum part length. int worst_case_length = length << 3; return CurrentPartCanFit(worst_case_length) ? worst_case_length : 0; } void AppendString(Handle<String> string); MaybeHandle<String> Finish(); V8_INLINE bool HasOverflowed() const { return overflowed_; } int Length() const; // Change encoding to two-byte. void ChangeEncoding() { DCHECK_EQ(String::ONE_BYTE_ENCODING, encoding_); ShrinkCurrentPart(); encoding_ = String::TWO_BYTE_ENCODING; Extend(); } template <typename DestChar> class NoExtend { public: NoExtend(Tagged<String> string, int offset, const DisallowGarbageCollection& no_gc) { DCHECK(IsSeqOneByteString(string) || IsSeqTwoByteString(string)); if (sizeof(DestChar) == 1) { start_ = reinterpret_cast<DestChar*>( SeqOneByteString::cast(string)->GetChars(no_gc) + offset); } else { start_ = reinterpret_cast<DestChar*>( SeqTwoByteString::cast(string)->GetChars(no_gc) + offset); } cursor_ = start_; #ifdef DEBUG string_ = string; #endif } #ifdef DEBUG ~NoExtend() { DestChar* end; if (sizeof(DestChar) == 1) { auto one_byte_string = SeqOneByteString::cast(string_); end = reinterpret_cast<DestChar*>(one_byte_string->GetChars(no_gc_) + one_byte_string->length()); } else { auto two_byte_string = SeqTwoByteString::cast(string_); end = reinterpret_cast<DestChar*>(two_byte_string->GetChars(no_gc_) + two_byte_string->length()); } DCHECK_LE(cursor_, end + 1); } #endif V8_INLINE void Append(DestChar c) { *(cursor_++) = c; } V8_INLINE void AppendCString(const char* s) { const uint8_t* u = reinterpret_cast<const uint8_t*>(s); while (*u != '\0') Append(*(u++)); } int written() { return static_cast<int>(cursor_ - start_); } private: DestChar* start_; DestChar* cursor_; #ifdef DEBUG Tagged<String> string_; #endif DISALLOW_GARBAGE_COLLECTION(no_gc_) }; template <typename DestChar> class NoExtendBuilder : public NoExtend<DestChar> { public: NoExtendBuilder(IncrementalStringBuilder* builder, int required_length, const DisallowGarbageCollection& no_gc) : NoExtend<DestChar>(*(builder->current_part()), builder->current_index_, no_gc), builder_(builder) { DCHECK(builder->CurrentPartCanFit(required_length)); } ~NoExtendBuilder() { builder_->current_index_ += NoExtend<DestChar>::written(); DCHECK(builder_->HasValidCurrentIndex()); } private: IncrementalStringBuilder* builder_; }; Isolate* isolate() { return isolate_; } private: Factory* factory() { return isolate_->factory(); } V8_INLINE Handle<String> accumulator() { return accumulator_; } V8_INLINE void set_accumulator(Handle<String> string) { accumulator_.PatchValue(*string); } V8_INLINE Handle<String> current_part() { return current_part_; } V8_INLINE void set_current_part(Handle<String> string) { current_part_.PatchValue(*string); } // Add the current part to the accumulator. void Accumulate(Handle<String> new_part); // Finish the current part and allocate a new part. void Extend(); bool HasValidCurrentIndex() const; // Shrink current part to the right size. void ShrinkCurrentPart() { DCHECK(current_index_ < part_length_); set_current_part(SeqString::Truncate( isolate_, Handle<SeqString>::cast(current_part()), current_index_)); } void AppendStringByCopy(Handle<String> string); bool CanAppendByCopy(Handle<String> string); static const int kInitialPartLength = 32; static const int kMaxPartLength = 16 * 1024; static const int kPartLengthGrowthFactor = 2; static const int kIntToCStringBufferSize = 100; Isolate* isolate_; String::Encoding encoding_; bool overflowed_; int part_length_; int current_index_; Handle<String> accumulator_; Handle<String> current_part_; }; template <typename SrcChar, typename DestChar> void IncrementalStringBuilder::Append(SrcChar c) { DCHECK_EQ(encoding_ == String::ONE_BYTE_ENCODING, sizeof(DestChar) == 1); if (sizeof(DestChar) == 1) { DCHECK_EQ(String::ONE_BYTE_ENCODING, encoding_); SeqOneByteString::cast(*current_part_) ->SeqOneByteStringSet(current_index_++, c); } else { DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding_); SeqTwoByteString::cast(*current_part_) ->SeqTwoByteStringSet(current_index_++, c); } if (current_index_ == part_length_) Extend(); DCHECK(HasValidCurrentIndex()); } } // namespace internal } // namespace v8 #endif // V8_STRINGS_STRING_BUILDER_INL_H_