1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
// Copyright 2025 Steven Le Rouzic
//
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
#include "asl/containers/buffer.hpp"
#include "asl/strings/string.hpp"
#include "asl/strings/string_view.hpp"
#include "asl/formatting/format.hpp"
#include "asl/io/writer.hpp"
namespace asl
{
template<allocator Allocator = DefaultAllocator>
class StringBuilder
{
buffer<char, Allocator> m_buffer;
public:
constexpr StringBuilder() requires default_constructible<Allocator> = default;
explicit constexpr StringBuilder(Allocator allocator) : m_buffer{std::move(allocator)} {}
constexpr ~StringBuilder() = default;
constexpr StringBuilder(const StringBuilder&) requires copy_constructible<Allocator> = default;
constexpr StringBuilder(StringBuilder&&) = default;
constexpr StringBuilder& operator=(const StringBuilder&) requires copy_assignable<Allocator> = default;
constexpr StringBuilder& operator=(StringBuilder&&) = default;
[[nodiscard]] constexpr string_view as_string_view() const
{
auto span = m_buffer.as_span();
return string_view{span.data(), span.size()};
}
void reset()
{
m_buffer.clear();
}
auto push(this auto&& self, string_view sv) -> decltype(self)
requires (!is_const<un_ref_t<decltype(self)>>)
{
const isize_t old_size = self.m_buffer.size();
self.m_buffer.resize_uninit(old_size + sv.size());
// NOLINTNEXTLINE(*-pointer-arithmetic)
asl::memcpy(self.m_buffer.data() + old_size, sv.data(), sv.size());
return std::forward<decltype(self)>(self);
}
auto push(this auto&& self, char c) -> decltype(self)
requires (!is_const<un_ref_t<decltype(self)>>)
{
self.m_buffer.push(c);
return std::forward<decltype(self)>(self);
}
string<Allocator> finish() &&
{
return string<Allocator>{std::move(m_buffer)};
}
template<allocator StringAllocator = Allocator>
string<StringAllocator> as_string() const
requires default_constructible<StringAllocator>
{
return string<StringAllocator>{as_string_view()};
}
template<allocator StringAllocator = Allocator>
string<StringAllocator> as_string(Allocator allocator) const
{
return string<StringAllocator>{as_string_view(), std::move(allocator)};
}
};
StringBuilder() -> StringBuilder<>;
template<typename Allocator = DefaultAllocator>
class StringWriter : public asl::Writer
{
StringBuilder<Allocator> m_builder;
public:
constexpr StringWriter() requires default_constructible<Allocator> = default;
explicit constexpr StringWriter(Allocator allocator) : m_builder{std::move(allocator)} {}
constexpr ~StringWriter() override = default;
constexpr StringWriter(const StringWriter&) requires copy_constructible<Allocator> = default;
constexpr StringWriter(StringWriter&&) = default;
constexpr StringWriter& operator=(const StringWriter&) requires copy_assignable<Allocator> = default;
constexpr StringWriter& operator=(StringWriter&&) = default;
void write(span<const byte> str) override
{
// NOLINTNEXTLINE(*-reinterpret-cast)
m_builder.push(string_view{reinterpret_cast<const char*>(str.data()), str.size()});
}
[[nodiscard]] constexpr string_view as_string_view() const
{
return m_builder.as_string_view();
}
string<Allocator> finish() &&
{
return std::move(m_builder).finish();
}
template<allocator StringAllocator = Allocator>
string<StringAllocator> as_string() const
requires default_constructible<StringAllocator>
{
return m_builder.as_string();
}
template<allocator StringAllocator = Allocator>
string<StringAllocator> as_string(Allocator allocator) const
{
return m_builder.as_string(std::move(allocator));
}
};
StringWriter() -> StringWriter<>;
template<allocator Allocator = DefaultAllocator>
string<Allocator> format_to_string(string_view fmt, const formattable auto&... args)
requires default_constructible<Allocator>
{
StringWriter writer{};
format(&writer, fmt, args...);
return std::move(writer).finish();
}
template<allocator Allocator = DefaultAllocator>
string<Allocator> format_to_string(Allocator allocator, string_view fmt, const formattable auto&... args)
{
StringWriter writer{std::move(allocator)};
format(&writer, fmt, args...);
return std::move(writer).finish();
}
} // namespace asl
|