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/optimization.h"
14 #include "src/stdio/printf_core/core_structs.h"
15 #include "src/string/memory_utils/inline_memcpy.h"
16 #include "src/string/memory_utils/inline_memset.h"
20 namespace LIBC_NAMESPACE
{
21 namespace printf_core
{
24 using StreamWriter
= int (*)(cpp::string_view
, void *);
26 const size_t buff_len
;
29 // The stream writer will be called when the buffer is full. It will be passed
30 // string_views to write to the stream.
31 StreamWriter stream_writer
;
34 LIBC_INLINE
WriteBuffer(char *Buff
, size_t Buff_len
, StreamWriter hook
,
36 : buff(Buff
), buff_len(Buff_len
), stream_writer(hook
),
37 output_target(target
) {}
39 LIBC_INLINE
WriteBuffer(char *Buff
, size_t Buff_len
)
40 : buff(Buff
), buff_len(Buff_len
), stream_writer(nullptr),
41 output_target(nullptr) {}
43 // The overflow_write method is intended to be called to write the contents of
44 // the buffer and new_str to the stream_writer if it exists, else it will
45 // write as much of new_str to the buffer as it can. The current position in
46 // the buffer will be reset iff stream_writer is called. Calling this with an
47 // empty string will flush the buffer if relevant.
48 int overflow_write(cpp::string_view new_str
) {
49 // If there is a stream_writer, write the contents of the buffer, then
50 // new_str, then clear the buffer.
51 if (stream_writer
!= nullptr) {
53 int retval
= stream_writer({buff
, buff_cur
}, output_target
);
58 if (new_str
.size() > 0) {
59 int retval
= stream_writer(new_str
, output_target
);
67 // We can't flush to the stream, so fill the rest of the buffer, then drop
69 if (buff_cur
< buff_len
) {
70 size_t bytes_to_write
= buff_len
- buff_cur
;
71 if (bytes_to_write
> new_str
.size()) {
72 bytes_to_write
= new_str
.size();
74 inline_memcpy(buff
+ buff_cur
, new_str
.data(), bytes_to_write
);
75 buff_cur
+= bytes_to_write
;
84 int chars_written
= 0;
86 // This is a separate, non-inlined function so that the inlined part of the
87 // write function is shorter.
88 int pad(char new_char
, size_t length
);
91 LIBC_INLINE
Writer(WriteBuffer
*WB
) : wb(WB
) {}
93 // Takes a string, copies it into the buffer if there is space, else passes it
94 // to the overflow mechanism to be handled separately.
95 LIBC_INLINE
int write(cpp::string_view new_string
) {
96 chars_written
+= static_cast<int>(new_string
.size());
97 if (LIBC_LIKELY(wb
->buff_cur
+ new_string
.size() <= wb
->buff_len
)) {
98 inline_memcpy(wb
->buff
+ wb
->buff_cur
, new_string
.data(),
100 wb
->buff_cur
+= new_string
.size();
103 return wb
->overflow_write(new_string
);
106 // Takes a char and a length, memsets the next length characters of the buffer
107 // if there is space, else calls pad which will loop and call the overflow
108 // mechanism on a secondary buffer.
109 LIBC_INLINE
int write(char new_char
, size_t length
) {
110 chars_written
+= static_cast<int>(length
);
112 if (LIBC_LIKELY(wb
->buff_cur
+ length
<= wb
->buff_len
)) {
113 inline_memset(wb
->buff
+ wb
->buff_cur
, new_char
, length
);
114 wb
->buff_cur
+= length
;
117 return pad(new_char
, length
);
120 // Takes a char, copies it into the buffer if there is space, else passes it
121 // to the overflow mechanism to be handled separately.
122 LIBC_INLINE
int write(char new_char
) {
124 if (LIBC_LIKELY(wb
->buff_cur
+ 1 <= wb
->buff_len
)) {
125 wb
->buff
[wb
->buff_cur
] = new_char
;
129 cpp::string_view
char_string_view(&new_char
, 1);
130 return wb
->overflow_write(char_string_view
);
133 LIBC_INLINE
int get_chars_written() { return chars_written
; }
136 } // namespace printf_core
137 } // namespace LIBC_NAMESPACE
139 #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITER_H