#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITER_H
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITER_H
#include "src/__support/CPP/string_view.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/optimization.h"
#include "src/stdio/printf_core/core_structs.h"
#include "src/string/memory_utils/inline_memcpy.h"
#include "src/string/memory_utils/inline_memset.h"
#include <stddef.h>
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
struct WriteBuffer {
using StreamWriter = int (*)(cpp::string_view, void *);
char *buff;
const size_t buff_len;
size_t buff_cur = 0;
StreamWriter stream_writer;
void *output_target;
LIBC_INLINE WriteBuffer(char *Buff, size_t Buff_len, StreamWriter hook,
void *target)
: buff(Buff), buff_len(Buff_len), stream_writer(hook),
output_target(target) {}
LIBC_INLINE WriteBuffer(char *Buff, size_t Buff_len)
: buff(Buff), buff_len(Buff_len), stream_writer(nullptr),
output_target(nullptr) {}
LIBC_INLINE int overflow_write(cpp::string_view new_str) {
if (stream_writer != nullptr) {
if (buff_cur > 0) {
int retval = stream_writer({buff, buff_cur}, output_target);
if (retval < 0) {
return retval;
}
}
if (new_str.size() > 0) {
int retval = stream_writer(new_str, output_target);
if (retval < 0) {
return retval;
}
}
buff_cur = 0;
return WRITE_OK;
} else {
if (buff_cur < buff_len) {
size_t bytes_to_write = buff_len - buff_cur;
if (bytes_to_write > new_str.size()) {
bytes_to_write = new_str.size();
}
inline_memcpy(buff + buff_cur, new_str.data(), bytes_to_write);
buff_cur += bytes_to_write;
}
return WRITE_OK;
}
}
};
class Writer final {
WriteBuffer *wb;
int chars_written = 0;
int pad(char new_char, size_t length);
public:
LIBC_INLINE Writer(WriteBuffer *WB) : wb(WB) {}
LIBC_INLINE int write(cpp::string_view new_string) {
chars_written += static_cast<int>(new_string.size());
if (LIBC_LIKELY(wb->buff_cur + new_string.size() <= wb->buff_len)) {
inline_memcpy(wb->buff + wb->buff_cur, new_string.data(),
new_string.size());
wb->buff_cur += new_string.size();
return WRITE_OK;
}
return wb->overflow_write(new_string);
}
LIBC_INLINE int write(char new_char, size_t length) {
chars_written += static_cast<int>(length);
if (LIBC_LIKELY(wb->buff_cur + length <= wb->buff_len)) {
inline_memset(wb->buff + wb->buff_cur, new_char, length);
wb->buff_cur += length;
return WRITE_OK;
}
return pad(new_char, length);
}
LIBC_INLINE int write(char new_char) {
chars_written += 1;
if (LIBC_LIKELY(wb->buff_cur + 1 <= wb->buff_len)) {
wb->buff[wb->buff_cur] = new_char;
wb->buff_cur += 1;
return WRITE_OK;
}
cpp::string_view char_string_view(&new_char, 1);
return wb->overflow_write(char_string_view);
}
LIBC_INLINE int get_chars_written() { return chars_written; }
};
}
}
#endif