[libc] Use best-fit binary trie to make malloc logarithmic (#106259)
[llvm-project.git] / libc / src / stdio / printf_core / writer.h
blob5526a478ea620ecd59f74977177e6b051727c379
1 //===-- Writer definition for printf ----------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITER_H
10 #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITER_H
12 #include "src/__support/CPP/string_view.h"
13 #include "src/__support/macros/config.h"
14 #include "src/__support/macros/optimization.h"
15 #include "src/stdio/printf_core/core_structs.h"
16 #include "src/string/memory_utils/inline_memcpy.h"
17 #include "src/string/memory_utils/inline_memset.h"
19 #include <stddef.h>
21 namespace LIBC_NAMESPACE_DECL {
22 namespace printf_core {
24 struct WriteBuffer {
25 enum class WriteMode {
26 FILL_BUFF_AND_DROP_OVERFLOW,
27 FLUSH_TO_STREAM,
28 RESIZE_AND_FILL_BUFF,
30 using StreamWriter = int (*)(cpp::string_view, void *);
31 char *buff;
32 const char *init_buff; // for checking when resize.
33 size_t buff_len;
34 size_t buff_cur = 0;
36 // The stream writer will be called when the buffer is full. It will be passed
37 // string_views to write to the stream.
38 StreamWriter stream_writer;
39 void *output_target;
40 WriteMode write_mode;
42 LIBC_INLINE WriteBuffer(char *Buff, size_t Buff_len, StreamWriter hook,
43 void *target)
44 : buff(Buff), init_buff(Buff), buff_len(Buff_len), stream_writer(hook),
45 output_target(target), write_mode(WriteMode::FLUSH_TO_STREAM) {}
47 LIBC_INLINE WriteBuffer(char *Buff, size_t Buff_len)
48 : buff(Buff), init_buff(Buff), buff_len(Buff_len), stream_writer(nullptr),
49 output_target(nullptr),
50 write_mode(WriteMode::FILL_BUFF_AND_DROP_OVERFLOW) {}
52 LIBC_INLINE WriteBuffer(char *Buff, size_t Buff_len, StreamWriter hook)
53 : buff(Buff), init_buff(Buff), buff_len(Buff_len), stream_writer(hook),
54 output_target(this), write_mode(WriteMode::RESIZE_AND_FILL_BUFF) {}
56 LIBC_INLINE int flush_to_stream(cpp::string_view new_str) {
57 if (buff_cur > 0) {
58 int retval = stream_writer({buff, buff_cur}, output_target);
59 if (retval < 0)
60 return retval;
62 if (new_str.size() > 0) {
63 int retval = stream_writer(new_str, output_target);
64 if (retval < 0)
65 return retval;
67 buff_cur = 0;
68 return WRITE_OK;
71 LIBC_INLINE int fill_remaining_to_buff(cpp::string_view new_str) {
72 if (buff_cur < buff_len) {
73 size_t bytes_to_write = buff_len - buff_cur;
74 if (bytes_to_write > new_str.size()) {
75 bytes_to_write = new_str.size();
77 inline_memcpy(buff + buff_cur, new_str.data(), bytes_to_write);
78 buff_cur += bytes_to_write;
80 return WRITE_OK;
83 LIBC_INLINE int resize_and_write(cpp::string_view new_str) {
84 return stream_writer(new_str, output_target);
87 // The overflow_write method is intended to be called to write the contents of
88 // the buffer and new_str to the stream_writer if it exists. If a resizing
89 // hook is provided, it will resize the buffer and write the contents. If
90 // neither a stream_writer nor a resizing hook is provided, it will fill the
91 // remaining space in the buffer with new_str and drop the overflow. Calling
92 // this with an empty string will flush the buffer if relevant.
94 LIBC_INLINE int overflow_write(cpp::string_view new_str) {
95 switch (write_mode) {
96 case WriteMode::FILL_BUFF_AND_DROP_OVERFLOW:
97 return fill_remaining_to_buff(new_str);
98 case WriteMode::FLUSH_TO_STREAM:
99 return flush_to_stream(new_str);
100 case WriteMode::RESIZE_AND_FILL_BUFF:
101 return resize_and_write(new_str);
103 __builtin_unreachable();
107 class Writer final {
108 WriteBuffer *wb;
109 int chars_written = 0;
111 // This is a separate, non-inlined function so that the inlined part of the
112 // write function is shorter.
113 int pad(char new_char, size_t length);
115 public:
116 LIBC_INLINE Writer(WriteBuffer *WB) : wb(WB) {}
118 // Takes a string, copies it into the buffer if there is space, else passes it
119 // to the overflow mechanism to be handled separately.
120 LIBC_INLINE int write(cpp::string_view new_string) {
121 chars_written += static_cast<int>(new_string.size());
122 if (LIBC_LIKELY(wb->buff_cur + new_string.size() <= wb->buff_len)) {
123 inline_memcpy(wb->buff + wb->buff_cur, new_string.data(),
124 new_string.size());
125 wb->buff_cur += new_string.size();
126 return WRITE_OK;
128 return wb->overflow_write(new_string);
131 // Takes a char and a length, memsets the next length characters of the buffer
132 // if there is space, else calls pad which will loop and call the overflow
133 // mechanism on a secondary buffer.
134 LIBC_INLINE int write(char new_char, size_t length) {
135 chars_written += static_cast<int>(length);
137 if (LIBC_LIKELY(wb->buff_cur + length <= wb->buff_len)) {
138 inline_memset(wb->buff + wb->buff_cur, new_char, length);
139 wb->buff_cur += length;
140 return WRITE_OK;
142 return pad(new_char, length);
145 // Takes a char, copies it into the buffer if there is space, else passes it
146 // to the overflow mechanism to be handled separately.
147 LIBC_INLINE int write(char new_char) {
148 chars_written += 1;
149 if (LIBC_LIKELY(wb->buff_cur + 1 <= wb->buff_len)) {
150 wb->buff[wb->buff_cur] = new_char;
151 wb->buff_cur += 1;
152 return WRITE_OK;
154 cpp::string_view char_string_view(&new_char, 1);
155 return wb->overflow_write(char_string_view);
158 LIBC_INLINE int get_chars_written() { return chars_written; }
161 } // namespace printf_core
162 } // namespace LIBC_NAMESPACE_DECL
164 #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITER_H