OutputFormatHelper.h
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * C++ Insights, copyright (C) by Andreas Fertig
4 * Distributed under an MIT license. See LICENSE for details
5 *
6 ****************************************************************************/
7
8#ifndef OUTPUT_FORMAT_HELPER_H
9#define OUTPUT_FORMAT_HELPER_H
10//-----------------------------------------------------------------------------
11
12#include <string_view>
13#include <utility>
14using namespace std::literals;
15
16#include "InsightsOnce.h"
17#include "InsightsStrCat.h"
18#include "InsightsStrongTypes.h"
19//-----------------------------------------------------------------------------
20
21namespace clang::insights {
22//-----------------------------------------------------------------------------
23
24/// \brief The C++ Insights formatter.
25///
26/// Most of the code is handed to \ref OutputFormatHelper for easy code formatting.
28{
29public:
30 OutputFormatHelper() = default;
31
32 explicit OutputFormatHelper(const unsigned indent)
33 : mDefaultIndent{indent}
34 {
35 }
36
37 operator std::string_view() const& { return {mOutput}; }
38
39 auto size() const { return mOutput.size(); }
40
41 /// \brief Returns the current position in the output buffer.
42 size_t CurrentPos() const { return mOutput.length(); }
43
44 /// \brief Insert a string before the position \c atPos
45 void InsertAt(const size_t atPos, std::string_view data) { mOutput.insert(atPos, data); }
46
47 STRONG_BOOL(SkipIndenting);
48
49 auto GetIndent() const { return mDefaultIndent; }
50
51 /// \brief Set the indent level of this class to \c indent.
52 void SetIndent(const unsigned indent, const SkipIndenting skipIndenting = SkipIndenting::No)
53 {
54 mDefaultIndent = indent;
55
56 if(SkipIndenting::No == skipIndenting) {
57 Indent(mDefaultIndent);
58 }
59 }
60
61 /// \brief Set the indent level of this class to that of \c rhs.
62 void SetIndent(const OutputFormatHelper& rhs, const SkipIndenting skipIndenting = SkipIndenting::No)
63 {
64 if(&rhs != this) {
65 mDefaultIndent = rhs.mDefaultIndent;
66
67 if(SkipIndenting::No == skipIndenting) {
68 Indent(mDefaultIndent);
69 }
70 }
71 }
72
73 /// \brief Check whether the buffer is empty.
74 ///
75 /// This also treats a string of just whitespaces as empty.
76 bool empty() const { return mOutput.empty() or (std::string::npos == mOutput.find_first_not_of(' ', 0)); }
77
78 /// \brief Returns a reference to the underlying string buffer.
79 std::string& GetString() { return mOutput; }
80
81 /// \brief Append a single character
82 ///
83 /// Append a single character to the buffer
84 void Append(const char c) { mOutput += c; }
85
86 void Append(const std::string_view& arg) { mOutput += arg; }
87
88 /// \brief Append a variable number of data
89 ///
90 /// The \c StrCat function which is used ensures, that a \c StringRef or a char are converted appropriately.
91 void Append(const auto&... args) { details::StrCat(mOutput, args...); }
92
93 /// \brief Same as \ref Append but adds a newline after the last argument.
94 ///
95 /// Append a single character to the buffer
96 void AppendNewLine(const char c)
97 {
98 mOutput += c;
99 NewLine();
100 }
101
102 void AppendNewLine(const std::string_view& arg)
103 {
104 mOutput += arg;
105 NewLine();
106 }
107
108 /// \brief Same as \ref Append but adds a newline after the last argument.
109 void AppendNewLine(const auto&... args)
110 {
111 if constexpr(0 < sizeof...(args)) {
112 details::StrCat(mOutput, args...);
113 }
114
115 NewLine();
116 }
117
118 void AppendComment(const std::string_view& arg)
119 {
120 Append("/* "sv);
121 Append(arg);
122 Append(" */"sv);
123 }
124
125 void AppendCommentNewLine(const std::string_view& arg)
126 {
127 AppendComment(arg);
128 NewLine();
129 }
130
131 void AppendCommentNewLine(const auto&... args)
132 {
133 if constexpr(0 < sizeof...(args)) {
134 AppendComment(StrCat(args...));
135 }
136
137 NewLine();
138 }
139
140 STRONG_BOOL(NameOnly);
141 STRONG_BOOL(GenMissingParamName);
142
143 /// \brief Append a \c ParamVarDecl array.
144 ///
145 /// The parameter name is always added as well.
146 void AppendParameterList(const ArrayRef<ParmVarDecl*> parameters,
147 const NameOnly nameOnly = NameOnly::No,
148 const GenMissingParamName genMissingParamName = GenMissingParamName::No);
149
150 /// \brief Increase the current indention by \c SCOPE_INDENT
151 void IncreaseIndent() { mDefaultIndent += SCOPE_INDENT; }
152 /// \brief Decrease the current indention by \c SCOPE_INDENT
154 {
155 if(mDefaultIndent >= SCOPE_INDENT) {
156 mDefaultIndent -= SCOPE_INDENT;
157 }
158 }
159
160 /// \brief Open a scope by inserting a '{' followed by an indented newline.
162 {
163 Append('{');
165 NewLine();
166 }
167
168 STRONG_BOOL(NoNewLineBefore);
169 /// \brief Close a scope by inserting a '}'
170 ///
171 /// With the parameter \c newLineBefore a newline after the brace can be inserted.
172 void CloseScope(const NoNewLineBefore newLineBefore = NoNewLineBefore::No);
173
174 /// \brief Similiar to \ref CloseScope only this time a ';' is inserted after the brace.
175 void CloseScopeWithSemi(const NoNewLineBefore newLineBefore = NoNewLineBefore::No)
176 {
177 CloseScope(newLineBefore);
178 Append(';');
179 }
180
181 /// \brief Append a comma if needed.
182 void AppendComma(OnceFalse& needsComma)
183 {
184 if(needsComma) {
185 Append(", "sv);
186 }
187 }
188
189 /// \brief Append a semicolon and a newline.
191
192 /// \brief Append a semicolon and a newline.
193 template<typename... Args>
194 void AppendSemiNewLine(const Args&... args)
195 {
196 if constexpr(0 < sizeof...(args)) {
197 details::StrCat(mOutput, args...);
198 }
199
200 AppendNewLine(';');
201 }
202
203 void AppendSemiNewLine(const std::string_view& arg)
204 {
205 mOutput += arg;
206 AppendNewLine(';');
207 }
208
209 /// \brief Append a argument list to the buffer.
210 ///
211 /// This function takes care of the delimiting ',' between the parameters. The lambda \c lambda is called to each
212 /// argument after the comma was inserted.
213 /// Usage:
214 /// \code
215 /// ForEachArg(parameters, [&](const auto& p) {
216 /// // do something with p
217 /// });
218 /// \endcode
219 inline void ForEachArg(const auto& arguments, /*XXX: invocable*/ auto&& lambda)
220 {
221 for(OnceFalse needsComma{}; const auto& arg : arguments) {
222 if constexpr(std::is_same_v<const TemplateArgument&, decltype(arg)>) {
223 if((TemplateArgument::Pack == arg.getKind()) and (0 == arg.pack_size())) {
224 break;
225 }
226 }
227
228 AppendComma(needsComma);
229
230 lambda(arg);
231 }
232 }
233
234 void InsertIfDefTemplateGuard() { AppendNewLine("#ifdef INSIGHTS_USE_TEMPLATE"sv); }
236
237private:
238 static constexpr unsigned SCOPE_INDENT{2};
239 unsigned mDefaultIndent{};
240 std::string mOutput{};
241
242 void Indent(unsigned count);
243 void NewLine()
244 {
245 mOutput += '\n';
246 Indent(mDefaultIndent);
247 }
248
249 void RemoveIndent();
250};
251//-----------------------------------------------------------------------------
252
253} // namespace clang::insights
254#endif /* OUTPUT_FORMAT_HELPER_H */
void DecreaseIndent()
Decrease the current indention by SCOPE_INDENT.
void OpenScope()
Open a scope by inserting a '{' followed by an indented newline.
void AppendNewLine(const char c)
Same as Append but adds a newline after the last argument.
void ForEachArg(const auto &arguments, auto &&lambda)
Append a argument list to the buffer.
void AppendParameterList(const ArrayRef< ParmVarDecl * > parameters, const NameOnly nameOnly=NameOnly::No, const GenMissingParamName genMissingParamName=GenMissingParamName::No)
Append a ParamVarDecl array.
void AppendComma(OnceFalse &needsComma)
Append a comma if needed.
void AppendComment(const std::string_view &arg)
STRONG_BOOL(GenMissingParamName)
void AppendCommentNewLine(const auto &... args)
void Append(const char c)
Append a single character.
OutputFormatHelper(const unsigned indent)
std::string & GetString()
Returns a reference to the underlying string buffer.
void Append(const std::string_view &arg)
void Append(const auto &... args)
Append a variable number of data.
void SetIndent(const OutputFormatHelper &rhs, const SkipIndenting skipIndenting=SkipIndenting::No)
Set the indent level of this class to that of rhs.
void CloseScopeWithSemi(const NoNewLineBefore newLineBefore=NoNewLineBefore::No)
Similiar to CloseScope only this time a ';' is inserted after the brace.
bool empty() const
Check whether the buffer is empty.
void CloseScope(const NoNewLineBefore newLineBefore=NoNewLineBefore::No)
Close a scope by inserting a '}'.
void AppendCommentNewLine(const std::string_view &arg)
void IncreaseIndent()
Increase the current indention by SCOPE_INDENT.
void AppendSemiNewLine(const Args &... args)
Append a semicolon and a newline.
void AppendSemiNewLine(const std::string_view &arg)
void SetIndent(const unsigned indent, const SkipIndenting skipIndenting=SkipIndenting::No)
Set the indent level of this class to indent.
void AppendNewLine(const auto &... args)
Same as Append but adds a newline after the last argument.
size_t CurrentPos() const
Returns the current position in the output buffer.
void AppendSemiNewLine()
Append a semicolon and a newline.
void AppendNewLine(const std::string_view &arg)
void InsertAt(const size_t atPos, std::string_view data)
Insert a string before the position atPos.
void StrCat(std::string &ret, const auto &... args)
std::string StrCat(const auto &... args)