• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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