80 char* currentIterator;
83 std::variant<StackBuffer, HeapBuffer> mBuffer;
88 auto& stack = std::get<StackBuffer>(mBuffer);
89 h.insert(h.end(), stack.buffer, stack.currentIterator);
90 mBuffer = std::move(h);
93 using value_type = char;
95 Buffer()
noexcept: mBuffer({}) {
96 auto& sb = std::get<StackBuffer>(mBuffer);
97 sb.currentIterator = sb.buffer;
99 size_t write(
const char* t,
size_t s) {
100 if (std::holds_alternative<StackBuffer>(mBuffer)) {
101 auto& stack = std::get<StackBuffer>(mBuffer);
102 if (stack.currentIterator + s <= stack.buffer +
sizeof(stack.buffer)) {
103 std::memcpy(stack.currentIterator, t, s);
104 stack.currentIterator += s;
109 auto& h = std::get<HeapBuffer>(mBuffer);
110 h.insert(h.end(), t, t + s);
114 if (std::holds_alternative<StackBuffer>(mBuffer)) {
115 auto& stack = std::get<StackBuffer>(mBuffer);
116 if (stack.currentIterator +
sizeof(c) <= stack.buffer +
sizeof(stack.buffer)) {
117 *stack.currentIterator = c;
118 stack.currentIterator += 1;
123 std::get<HeapBuffer>(mBuffer).push_back(c);
126 void push_back(
char c) {
131 std::string_view str()
const {
133 if (std::holds_alternative<StackBuffer>(mBuffer)) {
134 auto& stack = std::get<StackBuffer>(mBuffer);
135 return {stack.buffer,
static_cast<std::string_view::size_type
>(stack.currentIterator - stack.buffer) - 1};
137 auto& h = std::get<HeapBuffer>(mBuffer);
138 return {h.data(), h.size()};
142 struct LazyStreamBuf final: std::streambuf {
147 LazyStreamBuf(Buffer& stackBuffer) : stackBuffer(stackBuffer), stream(
this) {}
150 std::streamsize xsputn(
const char_type* s, std::streamsize n)
override {
151 return stackBuffer.write(s, n);
154 int overflow(int_type __c)
override {
155 stackBuffer.write(__c);
163 void writeTimestamp(
const char* fmt, std::chrono::system_clock::time_point t)
noexcept {
164 fmt::format_to(std::back_inserter(mBuffer),
"{}", t);
171 mPrefix(std::move(prefix)) {
177 auto s = mBuffer.str();
178 mLogger.log(mLevel, mPrefix.toStdString().c_str(), s);
182 LogWriter& operator<<(
const T& t)
noexcept {
184 if constexpr(std::is_constructible_v<std::string_view, T>) {
185 std::string_view stringView(t);
186 mBuffer.write(stringView.data(), stringView.size());
187 }
else if constexpr(std::is_base_of_v<AString, T>) {
188 *
this << t.toStdString();
189 }
else if constexpr(std::is_base_of_v<std::exception, T> && !std::is_base_of_v<AException, T>) {
190 *
this <<
"(" << AReflect::name(&t) <<
") " << t.what();
191 }
else if constexpr(std::is_same_v<std::chrono::seconds, T>) {
192 writeTimestamp(
"%D %T", std::chrono::system_clock::time_point(t));
193 }
else if constexpr(std::is_same_v<std::chrono::minutes, T> || std::is_same_v<std::chrono::hours, T>) {
194 writeTimestamp(
"%D %R", std::chrono::system_clock::time_point(t));
197 mStreamBuf.emplace(mBuffer);
199 mStreamBuf->stream << t;