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