1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2012 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker #ifndef ART_LIBARTBASE_BASE_INDENTER_H_ 18*795d594fSAndroid Build Coastguard Worker #define ART_LIBARTBASE_BASE_INDENTER_H_ 19*795d594fSAndroid Build Coastguard Worker 20*795d594fSAndroid Build Coastguard Worker #include <ostream> 21*795d594fSAndroid Build Coastguard Worker #include <streambuf> 22*795d594fSAndroid Build Coastguard Worker 23*795d594fSAndroid Build Coastguard Worker #include <android-base/logging.h> 24*795d594fSAndroid Build Coastguard Worker 25*795d594fSAndroid Build Coastguard Worker #include "macros.h" 26*795d594fSAndroid Build Coastguard Worker 27*795d594fSAndroid Build Coastguard Worker namespace art { 28*795d594fSAndroid Build Coastguard Worker 29*795d594fSAndroid Build Coastguard Worker constexpr char kIndentChar =' '; 30*795d594fSAndroid Build Coastguard Worker constexpr size_t kIndentBy1Count = 2; 31*795d594fSAndroid Build Coastguard Worker 32*795d594fSAndroid Build Coastguard Worker class Indenter : public std::streambuf { 33*795d594fSAndroid Build Coastguard Worker public: Indenter(std::streambuf * out,char text,size_t count)34*795d594fSAndroid Build Coastguard Worker Indenter(std::streambuf* out, char text, size_t count) 35*795d594fSAndroid Build Coastguard Worker : indent_next_(true), out_sbuf_(out), 36*795d594fSAndroid Build Coastguard Worker text_{text, text, text, text, text, text, text, text}, 37*795d594fSAndroid Build Coastguard Worker count_(count) {} 38*795d594fSAndroid Build Coastguard Worker 39*795d594fSAndroid Build Coastguard Worker private: xsputn(const char * s,std::streamsize n)40*795d594fSAndroid Build Coastguard Worker std::streamsize xsputn(const char* s, std::streamsize n) override { 41*795d594fSAndroid Build Coastguard Worker std::streamsize result = n; // Aborts on failure. 42*795d594fSAndroid Build Coastguard Worker const char* eol = static_cast<const char*>(memchr(s, '\n', n)); 43*795d594fSAndroid Build Coastguard Worker while (eol != nullptr) { 44*795d594fSAndroid Build Coastguard Worker size_t to_write = eol + 1 - s; 45*795d594fSAndroid Build Coastguard Worker Write(s, to_write); 46*795d594fSAndroid Build Coastguard Worker s += to_write; 47*795d594fSAndroid Build Coastguard Worker n -= to_write; 48*795d594fSAndroid Build Coastguard Worker indent_next_ = true; 49*795d594fSAndroid Build Coastguard Worker eol = static_cast<const char*>(memchr(s, '\n', n)); 50*795d594fSAndroid Build Coastguard Worker } 51*795d594fSAndroid Build Coastguard Worker if (n != 0u) { 52*795d594fSAndroid Build Coastguard Worker Write(s, n); 53*795d594fSAndroid Build Coastguard Worker } 54*795d594fSAndroid Build Coastguard Worker return result; 55*795d594fSAndroid Build Coastguard Worker } 56*795d594fSAndroid Build Coastguard Worker overflow(int_type c)57*795d594fSAndroid Build Coastguard Worker int_type overflow(int_type c) override { 58*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(c == std::char_traits<char>::eof())) { 59*795d594fSAndroid Build Coastguard Worker out_sbuf_->pubsync(); 60*795d594fSAndroid Build Coastguard Worker return c; 61*795d594fSAndroid Build Coastguard Worker } 62*795d594fSAndroid Build Coastguard Worker char data[1] = { static_cast<char>(c) }; 63*795d594fSAndroid Build Coastguard Worker Write(data, 1u); 64*795d594fSAndroid Build Coastguard Worker indent_next_ = (c == '\n'); 65*795d594fSAndroid Build Coastguard Worker return c; 66*795d594fSAndroid Build Coastguard Worker } 67*795d594fSAndroid Build Coastguard Worker sync()68*795d594fSAndroid Build Coastguard Worker int sync() override { 69*795d594fSAndroid Build Coastguard Worker return out_sbuf_->pubsync(); 70*795d594fSAndroid Build Coastguard Worker } 71*795d594fSAndroid Build Coastguard Worker Write(const char * s,std::streamsize n)72*795d594fSAndroid Build Coastguard Worker void Write(const char* s, std::streamsize n) { 73*795d594fSAndroid Build Coastguard Worker if (indent_next_) { 74*795d594fSAndroid Build Coastguard Worker size_t remaining = count_; 75*795d594fSAndroid Build Coastguard Worker while (remaining != 0u) { 76*795d594fSAndroid Build Coastguard Worker size_t to_write = std::min(remaining, sizeof(text_)); 77*795d594fSAndroid Build Coastguard Worker RawWrite(text_, to_write); 78*795d594fSAndroid Build Coastguard Worker remaining -= to_write; 79*795d594fSAndroid Build Coastguard Worker } 80*795d594fSAndroid Build Coastguard Worker indent_next_ = false; 81*795d594fSAndroid Build Coastguard Worker } 82*795d594fSAndroid Build Coastguard Worker RawWrite(s, n); 83*795d594fSAndroid Build Coastguard Worker } 84*795d594fSAndroid Build Coastguard Worker RawWrite(const char * s,std::streamsize n)85*795d594fSAndroid Build Coastguard Worker void RawWrite(const char* s, std::streamsize n) { 86*795d594fSAndroid Build Coastguard Worker size_t written = out_sbuf_->sputn(s, n); 87*795d594fSAndroid Build Coastguard Worker s += written; 88*795d594fSAndroid Build Coastguard Worker n -= written; 89*795d594fSAndroid Build Coastguard Worker while (n != 0u) { 90*795d594fSAndroid Build Coastguard Worker out_sbuf_->pubsync(); 91*795d594fSAndroid Build Coastguard Worker written = out_sbuf_->sputn(s, n); 92*795d594fSAndroid Build Coastguard Worker CHECK_NE(written, 0u) << "Error writing to buffer. Disk full?"; 93*795d594fSAndroid Build Coastguard Worker s += written; 94*795d594fSAndroid Build Coastguard Worker n -= written; 95*795d594fSAndroid Build Coastguard Worker } 96*795d594fSAndroid Build Coastguard Worker } 97*795d594fSAndroid Build Coastguard Worker 98*795d594fSAndroid Build Coastguard Worker bool indent_next_; 99*795d594fSAndroid Build Coastguard Worker 100*795d594fSAndroid Build Coastguard Worker // Buffer to write output to. 101*795d594fSAndroid Build Coastguard Worker std::streambuf* const out_sbuf_; 102*795d594fSAndroid Build Coastguard Worker 103*795d594fSAndroid Build Coastguard Worker // Text output as indent. 104*795d594fSAndroid Build Coastguard Worker const char text_[8]; 105*795d594fSAndroid Build Coastguard Worker 106*795d594fSAndroid Build Coastguard Worker // Number of times text is output. 107*795d594fSAndroid Build Coastguard Worker size_t count_; 108*795d594fSAndroid Build Coastguard Worker 109*795d594fSAndroid Build Coastguard Worker friend class VariableIndentationOutputStream; 110*795d594fSAndroid Build Coastguard Worker 111*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(Indenter); 112*795d594fSAndroid Build Coastguard Worker }; 113*795d594fSAndroid Build Coastguard Worker 114*795d594fSAndroid Build Coastguard Worker class VariableIndentationOutputStream { 115*795d594fSAndroid Build Coastguard Worker public: 116*795d594fSAndroid Build Coastguard Worker explicit VariableIndentationOutputStream(std::ostream* os, char text = kIndentChar) 117*795d594fSAndroid Build Coastguard Worker : indenter_(os->rdbuf(), text, 0u), 118*795d594fSAndroid Build Coastguard Worker indented_os_(&indenter_) { 119*795d594fSAndroid Build Coastguard Worker } 120*795d594fSAndroid Build Coastguard Worker Stream()121*795d594fSAndroid Build Coastguard Worker std::ostream& Stream() { 122*795d594fSAndroid Build Coastguard Worker return indented_os_; 123*795d594fSAndroid Build Coastguard Worker } 124*795d594fSAndroid Build Coastguard Worker GetIndentation()125*795d594fSAndroid Build Coastguard Worker size_t GetIndentation() const { 126*795d594fSAndroid Build Coastguard Worker return indenter_.count_; 127*795d594fSAndroid Build Coastguard Worker } 128*795d594fSAndroid Build Coastguard Worker IncreaseIndentation(size_t adjustment)129*795d594fSAndroid Build Coastguard Worker void IncreaseIndentation(size_t adjustment) { 130*795d594fSAndroid Build Coastguard Worker indenter_.count_ += adjustment; 131*795d594fSAndroid Build Coastguard Worker } 132*795d594fSAndroid Build Coastguard Worker DecreaseIndentation(size_t adjustment)133*795d594fSAndroid Build Coastguard Worker void DecreaseIndentation(size_t adjustment) { 134*795d594fSAndroid Build Coastguard Worker DCHECK_GE(indenter_.count_, adjustment); 135*795d594fSAndroid Build Coastguard Worker indenter_.count_ -= adjustment; 136*795d594fSAndroid Build Coastguard Worker } 137*795d594fSAndroid Build Coastguard Worker 138*795d594fSAndroid Build Coastguard Worker private: 139*795d594fSAndroid Build Coastguard Worker Indenter indenter_; 140*795d594fSAndroid Build Coastguard Worker std::ostream indented_os_; 141*795d594fSAndroid Build Coastguard Worker 142*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(VariableIndentationOutputStream); 143*795d594fSAndroid Build Coastguard Worker }; 144*795d594fSAndroid Build Coastguard Worker 145*795d594fSAndroid Build Coastguard Worker class ScopedIndentation { 146*795d594fSAndroid Build Coastguard Worker public: 147*795d594fSAndroid Build Coastguard Worker explicit ScopedIndentation(VariableIndentationOutputStream* vios, 148*795d594fSAndroid Build Coastguard Worker size_t adjustment = kIndentBy1Count) vios_(vios)149*795d594fSAndroid Build Coastguard Worker : vios_(vios), 150*795d594fSAndroid Build Coastguard Worker adjustment_(adjustment) { 151*795d594fSAndroid Build Coastguard Worker vios_->IncreaseIndentation(adjustment_); 152*795d594fSAndroid Build Coastguard Worker } 153*795d594fSAndroid Build Coastguard Worker ~ScopedIndentation()154*795d594fSAndroid Build Coastguard Worker ~ScopedIndentation() { 155*795d594fSAndroid Build Coastguard Worker vios_->DecreaseIndentation(adjustment_); 156*795d594fSAndroid Build Coastguard Worker } 157*795d594fSAndroid Build Coastguard Worker 158*795d594fSAndroid Build Coastguard Worker private: 159*795d594fSAndroid Build Coastguard Worker VariableIndentationOutputStream* const vios_; 160*795d594fSAndroid Build Coastguard Worker const size_t adjustment_; 161*795d594fSAndroid Build Coastguard Worker 162*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(ScopedIndentation); 163*795d594fSAndroid Build Coastguard Worker }; 164*795d594fSAndroid Build Coastguard Worker 165*795d594fSAndroid Build Coastguard Worker } // namespace art 166*795d594fSAndroid Build Coastguard Worker 167*795d594fSAndroid Build Coastguard Worker #endif // ART_LIBARTBASE_BASE_INDENTER_H_ 168