summaryrefslogtreecommitdiff
path: root/deps/v8/src/strings/string-builder-inl.h
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/strings/string-builder-inl.h')
-rw-r--r--deps/v8/src/strings/string-builder-inl.h310
1 files changed, 310 insertions, 0 deletions
diff --git a/deps/v8/src/strings/string-builder-inl.h b/deps/v8/src/strings/string-builder-inl.h
new file mode 100644
index 0000000000..88d69b37b5
--- /dev/null
+++ b/deps/v8/src/strings/string-builder-inl.h
@@ -0,0 +1,310 @@
+// 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"
+#include "src/utils/utils.h"
+
+namespace v8 {
+namespace internal {
+
+const int kStringBuilderConcatHelperLengthBits = 11;
+const int kStringBuilderConcatHelperPositionBits = 19;
+
+using StringBuilderSubstringLength =
+ BitField<int, 0, kStringBuilderConcatHelperLengthBits>;
+using StringBuilderSubstringPosition =
+ BitField<int, kStringBuilderConcatHelperLengthBits,
+ kStringBuilderConcatHelperPositionBits>;
+
+template <typename sinkchar>
+void StringBuilderConcatHelper(String special, sinkchar* sink,
+ FixedArray fixed_array, int array_length);
+
+// Returns the result length of the concatenation.
+// On illegal argument, -1 is returned.
+int StringBuilderConcatLength(int special_length, 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);
+
+ bool HasCapacity(int elements);
+ void EnsureCapacity(Isolate* isolate, int elements);
+
+ void Add(Object value);
+ void Add(Smi value);
+
+ Handle<FixedArray> array() { return array_; }
+
+ int length() { return length_; }
+
+ int capacity();
+
+ Handle<JSArray> ToJSArray(Handle<JSArray> target_array);
+
+ private:
+ 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, uc16>(c);
+ }
+ }
+
+ V8_INLINE void AppendCString(const char* s) {
+ const uint8_t* u = reinterpret_cast<const uint8_t*>(s);
+ if (encoding_ == String::ONE_BYTE_ENCODING) {
+ while (*u != '\0') Append<uint8_t, uint8_t>(*(u++));
+ } else {
+ while (*u != '\0') Append<uint8_t, uc16>(*(u++));
+ }
+ }
+
+ V8_INLINE void AppendCString(const uc16* s) {
+ if (encoding_ == String::ONE_BYTE_ENCODING) {
+ while (*s != '\0') Append<uc16, uint8_t>(*(s++));
+ } else {
+ while (*s != '\0') Append<uc16, uc16>(*(s++));
+ }
+ }
+
+ 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(Handle<String> string, int offset,
+ const DisallowHeapAllocation& no_gc) {
+ DCHECK(string->IsSeqOneByteString() || string->IsSeqTwoByteString());
+ if (sizeof(DestChar) == 1) {
+ start_ = reinterpret_cast<DestChar*>(
+ Handle<SeqOneByteString>::cast(string)->GetChars(no_gc) + offset);
+ } else {
+ start_ = reinterpret_cast<DestChar*>(
+ Handle<SeqTwoByteString>::cast(string)->GetChars(no_gc) + offset);
+ }
+ cursor_ = start_;
+ }
+
+ 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_;
+ DISALLOW_HEAP_ALLOCATION(no_gc_)
+ };
+
+ template <typename DestChar>
+ class NoExtendString : public NoExtend<DestChar> {
+ public:
+ NoExtendString(Handle<String> string, int required_length)
+ : NoExtend<DestChar>(string, 0), string_(string) {
+ DCHECK(string->length() >= required_length);
+ }
+
+ Handle<String> Finalize() {
+ Handle<SeqString> string = Handle<SeqString>::cast(string_);
+ int length = NoExtend<DestChar>::written();
+ Handle<String> result = SeqString::Truncate(string, length);
+ string_ = Handle<String>();
+ return result;
+ }
+
+ private:
+ Handle<String> string_;
+ };
+
+ template <typename DestChar>
+ class NoExtendBuilder : public NoExtend<DestChar> {
+ public:
+ NoExtendBuilder(IncrementalStringBuilder* builder, int required_length,
+ const DisallowHeapAllocation& 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();
+ }
+
+ private:
+ IncrementalStringBuilder* builder_;
+ };
+
+ private:
+ Factory* factory() { return isolate_->factory(); }
+
+ V8_INLINE Handle<String> accumulator() { return accumulator_; }
+
+ V8_INLINE void set_accumulator(Handle<String> string) {
+ *accumulator_.location() = string->ptr();
+ }
+
+ V8_INLINE Handle<String> current_part() { return current_part_; }
+
+ V8_INLINE void set_current_part(Handle<String> string) {
+ *current_part_.location() = string->ptr();
+ }
+
+ // Add the current part to the accumulator.
+ void Accumulate(Handle<String> new_part);
+
+ // Finish the current part and allocate a new part.
+ void Extend();
+
+ // Shrink current part to the right size.
+ void ShrinkCurrentPart() {
+ DCHECK(current_index_ < part_length_);
+ set_current_part(SeqString::Truncate(
+ Handle<SeqString>::cast(current_part()), current_index_));
+ }
+
+ static const int kInitialPartLength = 32;
+ static const int kMaxPartLength = 16 * 1024;
+ static const int kPartLengthGrowthFactor = 2;
+
+ 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();
+}
+} // namespace internal
+} // namespace v8
+
+#endif // V8_STRINGS_STRING_BUILDER_INL_H_