v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
string-builder.h
Go to the documentation of this file.
1// Copyright 2022 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#ifndef V8_WASM_STRING_BUILDER_H_
6#define V8_WASM_STRING_BUILDER_H_
7
8#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
10#endif // !V8_ENABLE_WEBASSEMBLY
11
12#include <cstring>
13#include <string>
14#include <vector>
15
16#include "src/common/globals.h"
17
18namespace v8 {
19namespace internal {
20namespace wasm {
21
22// Similar to std::ostringstream, but about 4x faster.
23// This base class works best for small-ish strings (up to kChunkSize); for
24// producing large amounts of text, you probably want a subclass like
25// MultiLineStringBuilder.
27 public:
29 explicit StringBuilder(const StringBuilder&) = delete;
32 for (char* chunk : chunks_) delete[] chunk;
34 delete[] start_;
35 }
36 }
37
38 // Reserves space for {n} characters and returns a pointer to its beginning.
39 // Clients *must* write all {n} characters after calling this!
40 // Don't call this directly, use operator<< overloads instead.
41 char* allocate(size_t n) {
42 if (remaining_bytes_ < n) Grow(n);
43 char* result = cursor_;
44 cursor_ += n;
46 return result;
47 }
48 // Convenience wrappers.
49 void write(const uint8_t* data, size_t n) {
50 char* ptr = allocate(n);
51 memcpy(ptr, data, n);
52 }
53 void write(const char* data, size_t n) {
54 char* ptr = allocate(n);
55 memcpy(ptr, data, n);
56 }
57
58 const char* start() const { return start_; }
59 const char* cursor() const { return cursor_; }
60 size_t length() const { return static_cast<size_t>(cursor_ - start_); }
65
66 // Erases the last character that was written. Calling this repeatedly
67 // isn't safe due to internal chunking of the backing store.
68 void backspace() {
70 cursor_--;
72 }
73
74 protected:
76
77 // Useful for subclasses that divide the text into ranges, e.g. lines.
78 explicit StringBuilder(OnGrowth on_growth) : on_growth_(on_growth) {}
80
82 static_assert(kChunkSize == size_t{MB});
83 return chunks_.size();
84 }
85
86 private:
87 void Grow(size_t requested) {
88 size_t used = length();
89 size_t required = used + requested;
90 size_t chunk_size;
92 // Usually grow by kChunkSize, unless super-long lines need even more.
93 chunk_size = required < kChunkSize ? kChunkSize : required * 2;
94 } else {
95 // When we only have one chunk, always (at least) double its size
96 // when it grows, to minimize both wasted memory and growth effort.
97 chunk_size = required * 2;
98 }
99
100 char* new_chunk = new char[chunk_size];
101 memcpy(new_chunk, start_, used);
102 if (on_growth_ == kKeepOldChunks) {
103 chunks_.push_back(new_chunk);
104 } else if (start_ != stack_buffer_) {
105 delete[] start_;
106 }
107 start_ = new_chunk;
108 cursor_ = new_chunk + used;
109 remaining_bytes_ = chunk_size - used;
110 }
111
112 // Start small, to be cheap for the common case.
113 static constexpr size_t kStackSize = 256;
114 // If we have to grow, grow in big steps.
115 static constexpr size_t kChunkSize = 1024 * 1024;
116
118 std::vector<char*> chunks_; // A very simple Zone, essentially.
123};
124
125inline StringBuilder& operator<<(StringBuilder& sb, const char* str) {
126 size_t len = strlen(str);
127 char* ptr = sb.allocate(len);
128 memcpy(ptr, str, len);
129 return sb;
130}
131
133 *sb.allocate(1) = c;
134 return sb;
135}
136
137inline StringBuilder& operator<<(StringBuilder& sb, const std::string& s) {
138 sb.write(s.data(), s.length());
139 return sb;
140}
141
142inline StringBuilder& operator<<(StringBuilder& sb, std::string_view s) {
143 sb.write(s.data(), s.length());
144 return sb;
145}
146
147inline StringBuilder& operator<<(StringBuilder& sb, uint32_t n) {
148 if (n == 0) {
149 *sb.allocate(1) = '0';
150 return sb;
151 }
152 static constexpr size_t kBufferSize = 10; // Just enough for a uint32.
153 char buffer[kBufferSize];
154 char* end = buffer + kBufferSize;
155 char* out = end;
156 while (n != 0) {
157 *(--out) = '0' + (n % 10);
158 n /= 10;
159 }
160 sb.write(out, static_cast<size_t>(end - out));
161 return sb;
162}
163
164inline StringBuilder& operator<<(StringBuilder& sb, int value) {
165 if (value >= 0) {
166 sb << static_cast<uint32_t>(value);
167 } else {
168 sb << "-" << ((~static_cast<uint32_t>(value)) + 1);
169 }
170 return sb;
171}
172
173} // namespace wasm
174} // namespace internal
175} // namespace v8
176
177#endif // V8_WASM_STRING_BUILDER_H_
static constexpr size_t kStackSize
StringBuilder(const StringBuilder &)=delete
static constexpr size_t kChunkSize
void write(const uint8_t *data, size_t n)
void write(const char *data, size_t n)
StringBuilder & operator=(const StringBuilder &)=delete
int end
ZoneVector< RpoNumber > & result
int n
Definition mul-fft.cc:296
std::ostream & operator<<(std::ostream &os, LiftoffVarState slot)
Definition c-api.cc:87
#define DCHECK_GT(v1, v2)
Definition logging.h:487