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