1
+ //
2
+ // Licensed under the Apache License v2.0 with LLVM Exceptions.
3
+ // See https://llvm.org/LICENSE.txt for license information.
4
+ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5
+ //
6
+ // Copyright (c) 2023 Vinnie Falco ([email protected] )
7
+ //
8
+ // Official repository: https://github.com/cppalliance/mrdox
9
+ //
10
+
11
+ #ifndef MRDOX_SUPPORT_FORMATTER_HPP
12
+ #define MRDOX_SUPPORT_FORMATTER_HPP
13
+
14
+ #include < mrdox/Platform.hpp>
15
+ #include < llvm/ADT/SmallVector.h>
16
+ #include < charconv>
17
+ #include < concepts>
18
+ #include < string_view>
19
+ #include < type_traits>
20
+
21
+ /* This API offers formatted output tailored to
22
+ the needs of generators that emit text.
23
+ */
24
+
25
+ namespace clang {
26
+ namespace mrdox {
27
+
28
+ struct format_tag {};
29
+
30
+ /* * Produces formatted output to a stream.
31
+ */
32
+ class Formatter
33
+ {
34
+ void * stream_;
35
+ void (*stream_fn_)(
36
+ void *, char const *, std::size_t );
37
+ std::string indent_;
38
+ bool needIndent_ = true ;
39
+
40
+ public:
41
+ /* * Constructor.
42
+ */
43
+ template <class Stream >
44
+ explicit
45
+ Formatter (
46
+ Stream& os) noexcept
47
+ : stream_(&os)
48
+ , stream_fn_(
49
+ [](void * os, char const * p, std::size_t n)
50
+ {
51
+ reinterpret_cast <Stream*>(os)->write (p, n);
52
+ })
53
+ {
54
+ }
55
+
56
+ /* * Set the indentation level.
57
+
58
+ @return The previous indentation level.
59
+ */
60
+ std::size_t indent (int n)
61
+ {
62
+ auto const n0 = indent_.size ();
63
+ indent_.resize (n0 + n, ' ' );
64
+ return n0;
65
+ }
66
+
67
+ /* * Write a line of formatted output.
68
+
69
+ This function efficiently converts each
70
+ argument to a string one at a time and
71
+ writes them to the output. After all the
72
+ arguments are written, a newline is emitted.
73
+
74
+ The string will be printed at the current
75
+ indentation level.
76
+ */
77
+ template <class Arg0 , class ... ArgN>
78
+ void
79
+ operator ()(Arg0&& arg0, ArgN&&... argn)
80
+ {
81
+ if constexpr (sizeof ...(argn) == 0 )
82
+ {
83
+ write (std::forward<Arg0>(arg0));
84
+ }
85
+ else
86
+ {
87
+ write (std::forward<Arg0>(arg0));
88
+ (*this )(std::forward<ArgN>(argn)...);
89
+ }
90
+ }
91
+
92
+ void operator ()() const noexcept = delete;
93
+
94
+ private:
95
+ // emit a newline
96
+ void write_newline ()
97
+ {
98
+ stream_fn_ (stream_, " \n " , 1 );
99
+ }
100
+
101
+ // write the string to the stream
102
+ void write_impl (std::string_view s)
103
+ {
104
+ auto it = s.data ();
105
+ auto const end = it + s.size ();
106
+ auto const flush =
107
+ [this ](auto it0, auto it)
108
+ {
109
+ if (needIndent_)
110
+ {
111
+ stream_fn_ (stream_, indent_.data (), indent_.size ());
112
+ needIndent_ = false ;
113
+ }
114
+ stream_fn_ (stream_, it0, it - it0);
115
+ };
116
+ for (;;)
117
+ {
118
+ if (it == end)
119
+ break ;
120
+ if (*it != ' \n ' )
121
+ {
122
+ do_chars:
123
+ auto it0 = it;
124
+ for (;;)
125
+ {
126
+ ++it;
127
+ if (it == end)
128
+ return flush (it0, it);
129
+ if (*it != ' \n ' )
130
+ continue ;
131
+ flush (it0, it);
132
+ break ;
133
+ }
134
+ }
135
+ needIndent_ = true ;
136
+ for (;;)
137
+ {
138
+ write_newline ();
139
+ ++it;
140
+ if (it == end)
141
+ return ;
142
+ if (*it == ' \n ' )
143
+ continue ;
144
+ goto do_chars;
145
+ }
146
+ }
147
+ }
148
+
149
+ // string literal
150
+ void write (char const * sz)
151
+ {
152
+ write_impl (std::string_view (sz));
153
+ }
154
+
155
+ // small string
156
+ void write (llvm::SmallVectorImpl<char > const & ss)
157
+ {
158
+ write_impl (std::string_view (ss.data (), ss.size ()));
159
+ }
160
+
161
+ void write (std::string const & s)
162
+ {
163
+ write_impl (std::string_view (s.data (), s.size ()));
164
+ }
165
+
166
+ // convertible to std::string_view
167
+ template <class T >
168
+ requires
169
+ std::is_convertible_v<T, std::string_view>
170
+ void write (T const & t)
171
+ {
172
+ write_impl (std::string_view (t));
173
+ }
174
+
175
+ // passed to std::to_chars
176
+ template <typename N>
177
+ requires
178
+ requires (N n) { std::to_chars (n); }
179
+ void write (N n)
180
+ {
181
+ write_impl (std::to_chars (n));
182
+ }
183
+
184
+ // call operator
185
+ template <class T >
186
+ void write (T const & t)
187
+ requires requires { t (*this ); }
188
+ {
189
+ t (*this );
190
+ }
191
+
192
+
193
+ // tag_invoke
194
+ template <class T >
195
+ void write (T const & t)
196
+ requires requires
197
+ {
198
+ tag_invoke (format_tag{}, *this , t);
199
+ }
200
+ {
201
+ tag_invoke (format_tag{}, *this , t);
202
+ }
203
+ };
204
+
205
+ } // mrdox
206
+ } // clang
207
+
208
+ #endif
0 commit comments