mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 09:00:22 +00:00
29879a69a4
Currently, invoking StringBuilder::to_string will re-allocate the string data to construct the String. This is wasteful both in terms of memory and speed. The goal here is to simply hand the string buffer over to String, and let String take ownership of that buffer. To do this, StringBuilder must have the same memory layout as Detail::StringData. This layout is just the members of the StringData class followed by the string itself. So when a StringBuilder is created, we reserve sizeof(StringData) bytes at the front of the buffer. StringData can then construct itself into the buffer with placement new. Things to note: * StringData must now be aware of the actual capacity of its buffer, as that can be larger than the string size. * We must take care not to pass ownership of inlined string buffers, as these live on the stack.
115 lines
3.4 KiB
C++
115 lines
3.4 KiB
C++
/*
|
|
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/ByteBuffer.h>
|
|
#include <AK/Format.h>
|
|
#include <AK/Forward.h>
|
|
#include <AK/StringView.h>
|
|
#include <stdarg.h>
|
|
|
|
namespace AK {
|
|
|
|
class StringBuilder {
|
|
public:
|
|
static constexpr size_t inline_capacity = 256;
|
|
|
|
using Buffer = Detail::ByteBuffer<inline_capacity>;
|
|
using OutputType = ByteString;
|
|
|
|
static ErrorOr<StringBuilder> create(size_t initial_capacity = inline_capacity);
|
|
|
|
explicit StringBuilder(size_t initial_capacity = inline_capacity);
|
|
~StringBuilder() = default;
|
|
|
|
ErrorOr<void> try_append(StringView);
|
|
ErrorOr<void> try_append(Utf16View const&);
|
|
ErrorOr<void> try_append(Utf32View const&);
|
|
ErrorOr<void> try_append_code_point(u32);
|
|
ErrorOr<void> try_append(char);
|
|
template<typename... Parameters>
|
|
ErrorOr<void> try_appendff(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
|
|
{
|
|
VariadicFormatParams<AllowDebugOnlyFormatters::No, Parameters...> variadic_format_params { parameters... };
|
|
return vformat(*this, fmtstr.view(), variadic_format_params);
|
|
}
|
|
ErrorOr<void> try_append(char const*, size_t);
|
|
ErrorOr<void> try_append_repeated(char, size_t);
|
|
ErrorOr<void> try_append_escaped_for_json(StringView);
|
|
|
|
void append(StringView);
|
|
void append(Utf16View const&);
|
|
void append(Utf32View const&);
|
|
void append(char);
|
|
void append_code_point(u32);
|
|
void append(char const*, size_t);
|
|
void appendvf(char const*, va_list);
|
|
void append_repeated(char, size_t);
|
|
|
|
void append_as_lowercase(char);
|
|
void append_escaped_for_json(StringView);
|
|
|
|
template<typename... Parameters>
|
|
void appendff(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
|
|
{
|
|
VariadicFormatParams<AllowDebugOnlyFormatters::No, Parameters...> variadic_format_params { parameters... };
|
|
MUST(vformat(*this, fmtstr.view(), variadic_format_params));
|
|
}
|
|
|
|
[[nodiscard]] ByteString to_byte_string() const;
|
|
|
|
[[nodiscard]] String to_string_without_validation();
|
|
ErrorOr<String> to_string();
|
|
|
|
[[nodiscard]] FlyString to_fly_string_without_validation() const;
|
|
ErrorOr<FlyString> to_fly_string() const;
|
|
|
|
[[nodiscard]] ErrorOr<ByteBuffer> to_byte_buffer() const;
|
|
|
|
[[nodiscard]] StringView string_view() const;
|
|
void clear();
|
|
|
|
[[nodiscard]] size_t length() const;
|
|
[[nodiscard]] bool is_empty() const;
|
|
void trim(size_t count);
|
|
|
|
template<class SeparatorType, class CollectionType>
|
|
void join(SeparatorType const& separator, CollectionType const& collection, StringView fmtstr = "{}"sv)
|
|
{
|
|
MUST(try_join(separator, collection, fmtstr));
|
|
}
|
|
|
|
template<class SeparatorType, class CollectionType>
|
|
ErrorOr<void> try_join(SeparatorType const& separator, CollectionType const& collection, StringView fmtstr = "{}"sv)
|
|
{
|
|
bool first = true;
|
|
for (auto& item : collection) {
|
|
if (!first)
|
|
TRY(try_append(separator));
|
|
TRY(try_appendff(fmtstr, item));
|
|
first = false;
|
|
}
|
|
return {};
|
|
}
|
|
|
|
Optional<Buffer::OutlineBuffer> leak_buffer_for_string_construction(Badge<Detail::StringData>);
|
|
|
|
private:
|
|
explicit StringBuilder(Buffer);
|
|
|
|
ErrorOr<void> will_append(size_t);
|
|
u8* data();
|
|
u8 const* data() const;
|
|
|
|
Buffer m_buffer;
|
|
};
|
|
|
|
}
|
|
|
|
#if USING_AK_GLOBALLY
|
|
using AK::StringBuilder;
|
|
#endif
|