| // Copyright 2024 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_H_ |
| #define V8_STRINGS_STRING_BUILDER_H_ |
| |
| #include "src/common/assert-scope.h" |
| #include "src/handles/handles.h" |
| #include "src/objects/heap-object.h" |
| #include "src/objects/string.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| class FixedArrayBuilder { |
| public: |
| explicit FixedArrayBuilder(Isolate* isolate, uint32_t initial_capacity); |
| explicit FixedArrayBuilder(DirectHandle<FixedArray> backing_store); |
| |
| // Creates a FixedArrayBuilder which allocates its backing store lazily when |
| // EnsureCapacity is called. |
| static FixedArrayBuilder Lazy(Isolate* isolate); |
| |
| bool HasCapacity(uint32_t elements); |
| void EnsureCapacity(Isolate* isolate, uint32_t elements); |
| |
| void Add(Tagged<Object> value); |
| void Add(Tagged<Smi> value); |
| |
| DirectHandle<FixedArray> array() { return array_; } |
| |
| // The functions return an alias instead of uint32_t to force appropriate |
| // conversions at the callsites. |
| SafeHeapObjectSize length() { return SafeHeapObjectSize(length_); } |
| |
| SafeHeapObjectSize capacity(); |
| |
| private: |
| explicit FixedArrayBuilder(Isolate* isolate); |
| |
| DirectHandle<FixedArray> array_; |
| uint32_t length_; |
| bool has_non_smi_elements_; |
| }; |
| |
| class ReplacementStringBuilder { |
| public: |
| ReplacementStringBuilder(Heap* heap, DirectHandle<String> subject, |
| uint32_t estimated_part_count); |
| |
| // Caution: Callers must ensure the builder has enough capacity. |
| static inline void AddSubjectSlice(FixedArrayBuilder* builder, int from, |
| int to); |
| |
| inline void AddSubjectSlice(int from, int to); |
| |
| void AddString(DirectHandle<String> string); |
| |
| MaybeDirectHandle<String> ToString(); |
| |
| void IncrementCharacterCount(uint32_t by) { |
| if (character_count_ > String::kMaxLength - by) { |
| static_assert(String::kMaxLength < kMaxInt); |
| character_count_ = kMaxInt; |
| } else { |
| character_count_ += by; |
| } |
| } |
| |
| private: |
| void AddElement(DirectHandle<Object> element); |
| void EnsureCapacity(uint32_t elements); |
| |
| Heap* heap_; |
| FixedArrayBuilder array_builder_; |
| DirectHandle<String> subject_; |
| uint32_t 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); |
| |
| template <int N> |
| V8_INLINE void AppendCStringLiteral(const char (&literal)[N]); |
| |
| template <typename SrcChar> |
| V8_INLINE void AppendCString(const SrcChar* s); |
| V8_INLINE void AppendString(std::string_view str); |
| |
| V8_INLINE void AppendInt(int i); |
| |
| 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. |
| V8_INLINE int EscapedLengthIfCurrentPartFits(int length); |
| |
| void AppendString(DirectHandle<String> string); |
| |
| // Appends {string} if its length is less than {max_length}, otherwise |
| // appends that prefix plus "<...>". Useful for error messages. |
| void AppendStringCapped(DirectHandle<String> string, uint32_t max_length); |
| |
| MaybeDirectHandle<String> Finish(); |
| |
| V8_INLINE bool HasOverflowed() const { return overflowed_; } |
| |
| int Length() const; |
| |
| // Change encoding to two-byte. |
| V8_INLINE void ChangeEncoding(); |
| |
| Isolate* isolate() { return isolate_; } |
| |
| private: |
| V8_INLINE Factory* factory(); |
| |
| V8_INLINE DirectHandle<String> accumulator() { return accumulator_; } |
| |
| V8_INLINE void set_accumulator(DirectHandle<String> string) { |
| accumulator_.SetValue(*string); |
| } |
| |
| V8_INLINE DirectHandle<String> current_part() { return current_part_; } |
| |
| V8_INLINE void set_current_part(DirectHandle<String> string) { |
| current_part_.SetValue(*string); |
| } |
| |
| // Add the current part to the accumulator. |
| void Accumulate(DirectHandle<String> new_part); |
| |
| // Finish the current part and allocate a new part. |
| void Extend(); |
| |
| bool HasValidCurrentIndex() const; |
| |
| // Shrink current part to the right size. |
| V8_INLINE void ShrinkCurrentPart(); |
| |
| void AppendStringByCopy(DirectHandle<String> string); |
| bool CanAppendByCopy(DirectHandle<String> string); |
| |
| static const int kInitialPartLength = 32; |
| static const int kMaxPartLength = 16 * 1024; |
| static const int kPartLengthGrowthFactor = 2; |
| // sizeof(string) includes \0. |
| static const int kIntToStringViewBufferSize = sizeof("-2147483648") - 1; |
| |
| Isolate* isolate_; |
| String::Encoding encoding_; |
| bool overflowed_; |
| int part_length_; |
| int current_index_; |
| DirectHandle<String> accumulator_; |
| DirectHandle<String> current_part_; |
| }; |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_STRINGS_STRING_BUILDER_H_ |