1 //===-- Writer definition for printf ----------------------------*- C++ -*-===//
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
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"
21 namespace LIBC_NAMESPACE_DECL
{
22 namespace printf_core
{
25 enum class WriteMode
{
26 FILL_BUFF_AND_DROP_OVERFLOW
,
30 using StreamWriter
= int (*)(cpp::string_view
, void *);
32 const char *init_buff
; // for checking when resize.
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
;
42 LIBC_INLINE
WriteBuffer(char *Buff
, size_t Buff_len
, StreamWriter hook
,
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
) {
58 int retval
= stream_writer({buff
, buff_cur
}, output_target
);
62 if (new_str
.size() > 0) {
63 int retval
= stream_writer(new_str
, output_target
);
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
;
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
) {
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();
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
);
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(),
125 wb
->buff_cur
+= new_string
.size();
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
;
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
) {
149 if (LIBC_LIKELY(wb
->buff_cur
+ 1 <= wb
->buff_len
)) {
150 wb
->buff
[wb
->buff_cur
] = new_char
;
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