1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef FORMATTER_H_
18
19 #define FORMATTER_H_
20
21 #include <functional>
22 #include <string>
23 #include <vector>
24
25 namespace android {
26
27 struct Formatter;
28
29 struct WrappedOutput {
30 WrappedOutput(size_t lineLength);
31
32 void group(const std::function<void(void)>& block);
33 WrappedOutput& operator<<(const std::string& str);
34 WrappedOutput& printUnlessWrapped(const std::string& str);
35
36 private:
37 struct Block {
38 Block(const std::string& content, Block* const parent);
39
40 // populated helps indicate if we are done filling up the Block.
41 // this allows WrappedOutput to keep adding content to this block
42 // till it is determined that it is full.
43 bool populated = false;
44 bool printUnlessWrapped = false;
45
46 // Only one of content or blocks can have content.
47 std::string content;
48 std::vector<Block> blocks;
49
50 Block* const parent;
51
52 size_t computeSize(bool wrapped) const;
53 void print(Formatter& out, bool wrapped) const;
54 };
55
56 size_t mLineLength;
57
58 Block mRootBlock;
59 Block* mCurrentBlock;
60
61 friend struct Formatter;
62 };
63
64 // Two styles to use a Formatter.
65 // One is with .indent() calls and operator<<.
66 // out << "if (good) {\n"; out.indent(); out << "blah\nblah\n"; out.unindent(); out << "}\n";
67 // The other is with chain calls and lambda functions
68 // out.sIf("good", [&] { out("blah").endl()("blah").endl(); }).endl();
69 struct Formatter {
invalidFormatter70 static Formatter invalid() { return Formatter(); }
71
72 // Assumes ownership of file. Directed to stdout if file == NULL.
73 Formatter(FILE* file, size_t spacesPerIndent = 4);
74 Formatter(Formatter&&) = default;
75 ~Formatter();
76
77 void indent(size_t level = 1);
78 void unindent(size_t level = 1);
79
80 // Note that The last \n after the last line is NOT added automatically.
81 // out.indent(2, [&] {
82 // out << "Meow\n";
83 // });
84 Formatter& indent(size_t level, const std::function<void(void)>& func);
85
86 // Note that The last \n after the last line is NOT added automatically.
87 // out.indent([&] {
88 // out << "Meow\n";
89 // });
90 Formatter& indent(const std::function<void(void)>& func);
91
92 // A block inside braces.
93 // * No space will be added before the opening brace.
94 // * The last \n before the closing brace is added automatically.
95 // * There will NOT be a \n after the closing brace.
96 // out.block([&] {
97 // out << "one();\n"
98 // << "two();\n";
99 // });
100 // is equivalent to
101 // out << "{\n"
102 // << "one();\ntwo();\n" // func()
103 // << "}";
104 Formatter& block(const std::function<void(void)>& func);
105
106 // A synonym to (*this) << "\n";
107 Formatter &endl();
108
109 // out.sIf("z == 1", [&] {
110 // out << "doGoodStuff();\n";
111 // }).sElseIf("z == 2", [&] {
112 // out << "doBadStuff();\n";
113 // }).sElse([&] {
114 // out << "logFatal();\n";
115 // }).endl();
116 // note that there will be a space before the "else"-s.
117 Formatter& sIf(const std::string& cond, const std::function<void(void)>& block);
118 Formatter& sElseIf(const std::string& cond, const std::function<void(void)>& block);
119 Formatter& sElse(const std::function<void(void)>& block);
120
121 // out.sFor("int i = 0; i < 10; i++", [&] {
122 // out << "printf(\"%d\", i);\n";
123 // }).endl();
124 Formatter& sFor(const std::string& stmts, const std::function<void(void)>& block);
125
126 // out.sTry([&] {
127 // out << "throw RemoteException();\n"
128 // }).sCatch("RemoteException ex", [&] {
129 // out << "ex.printStackTrace();\n"
130 // }).sFinally([&] {
131 // // cleanup
132 // }).endl();
133 // note that there will be a space before the "catch"-s.
134 Formatter& sTry(const std::function<void(void)>& block);
135 Formatter& sCatch(const std::string& exception, const std::function<void(void)>& block);
136 Formatter& sFinally(const std::function<void(void)>& block);
137
138 // out.sWhile("z < 10", [&] {
139 // out << "z++;\n";
140 // }).endl();
141 Formatter& sWhile(const std::string& cond, const std::function<void(void)>& block);
142
143 // out.join(v.begin(), v.end(), ",", [&](const auto &e) {
144 // out << toString(e);
145 // });
146 template <typename I>
147 Formatter& join(
148 const I begin, const I end, const std::string& separator,
149 const std::function<void(const typename std::iterator_traits<I>::value_type&)>& func);
150
151 Formatter &operator<<(const std::string &out);
152
153 Formatter &operator<<(char c);
154 Formatter &operator<<(signed char c);
155 Formatter &operator<<(unsigned char c);
156
157 Formatter &operator<<(short c);
158 Formatter &operator<<(unsigned short c);
159 Formatter &operator<<(int c);
160 Formatter &operator<<(unsigned int c);
161 Formatter &operator<<(long c);
162 Formatter &operator<<(unsigned long c);
163 Formatter &operator<<(long long c);
164 Formatter &operator<<(unsigned long long c);
165 Formatter &operator<<(float c);
166 Formatter &operator<<(double c);
167 Formatter &operator<<(long double c);
168 Formatter& operator<<(const WrappedOutput& wrappedOutput);
169
170 // Puts a prefix before each line. This is useful if
171 // you want to start a // comment block, for example.
172 // The prefix will be put before the indentation.
173 // Will be effective the next time cursor is at the start of line.
174 // Adding two prefixes will output them in the order they were added
175 void pushLinePrefix(const std::string& prefix);
176 // Remove the last line prefix.
177 void popLinePrefix();
178
179 bool isValid() const;
180 size_t getIndentation() const;
181
182 private:
183 // Creates an invalid formatter object.
184 Formatter();
185
186 FILE* mFile; // invalid if nullptr
187 size_t mIndentDepth;
188 size_t mSpacesPerIndent;
189 size_t mCurrentPosition;
190
191 std::vector<std::string> mLinePrefix;
192
193 void printBlock(const WrappedOutput::Block& block, size_t lineLength);
194 void output(const std::string &text) const;
195
196 Formatter(const Formatter&) = delete;
197 void operator=(const Formatter&) = delete;
198 };
199
200 template <typename I>
join(const I begin,const I end,const std::string & separator,const std::function<void (const typename std::iterator_traits<I>::value_type &)> & func)201 Formatter& Formatter::join(
202 const I begin, const I end, const std::string& separator,
203 const std::function<void(const typename std::iterator_traits<I>::value_type&)>& func) {
204 for (I iter = begin; iter != end; ++iter) {
205 if (iter != begin) {
206 (*this) << separator;
207 }
208 func(*iter);
209 }
210 return (*this);
211 }
212
213 } // namespace android
214
215 #endif // FORMATTER_H_
216
217