Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2012 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 ART_RUNTIME_INDENTER_H_
     18 #define ART_RUNTIME_INDENTER_H_
     19 
     20 #include "base/logging.h"
     21 #include "base/macros.h"
     22 #include <ostream>
     23 #include <streambuf>
     24 
     25 namespace art {
     26 
     27 constexpr char kIndentChar =' ';
     28 constexpr size_t kIndentBy1Count = 2;
     29 
     30 class Indenter : public std::streambuf {
     31  public:
     32   Indenter(std::streambuf* out, char text, size_t count)
     33       : indent_next_(true), out_sbuf_(out),
     34         text_{text, text, text, text, text, text, text, text},  // NOLINT(whitespace/braces)
     35         count_(count) {}
     36 
     37  private:
     38   std::streamsize xsputn(const char* s, std::streamsize n) OVERRIDE {
     39     std::streamsize result = n;  // Aborts on failure.
     40     const char* eol = static_cast<const char*>(memchr(s, '\n', n));
     41     while (eol != nullptr) {
     42       size_t to_write = eol + 1 - s;
     43       Write(s, to_write);
     44       s += to_write;
     45       n -= to_write;
     46       indent_next_ = true;
     47       eol = static_cast<const char*>(memchr(s, '\n', n));
     48     }
     49     if (n != 0u) {
     50       Write(s, n);
     51     }
     52     return result;
     53   }
     54 
     55   int_type overflow(int_type c) OVERRIDE {
     56     if (UNLIKELY(c == std::char_traits<char>::eof())) {
     57       out_sbuf_->pubsync();
     58       return c;
     59     }
     60     char data[1] = { static_cast<char>(c) };
     61     Write(data, 1u);
     62     indent_next_ = (c == '\n');
     63     return c;
     64   }
     65 
     66   int sync() {
     67     return out_sbuf_->pubsync();
     68   }
     69 
     70   void Write(const char* s, std::streamsize n) {
     71     if (indent_next_) {
     72       size_t remaining = count_;
     73       while (remaining != 0u) {
     74         size_t to_write = std::min(remaining, sizeof(text_));
     75         RawWrite(text_, to_write);
     76         remaining -= to_write;
     77       }
     78       indent_next_ = false;
     79     }
     80     RawWrite(s, n);
     81   }
     82 
     83   void RawWrite(const char* s, std::streamsize n) {
     84     size_t written = out_sbuf_->sputn(s, n);
     85     s += written;
     86     n -= written;
     87     while (n != 0u) {
     88       out_sbuf_->pubsync();
     89       written = out_sbuf_->sputn(s, n);
     90       CHECK_NE(written, 0u) << "Error writing to buffer. Disk full?";
     91       s += written;
     92       n -= written;
     93     }
     94   }
     95 
     96   bool indent_next_;
     97 
     98   // Buffer to write output to.
     99   std::streambuf* const out_sbuf_;
    100 
    101   // Text output as indent.
    102   const char text_[8];
    103 
    104   // Number of times text is output.
    105   size_t count_;
    106 
    107   friend class VariableIndentationOutputStream;
    108 
    109   DISALLOW_COPY_AND_ASSIGN(Indenter);
    110 };
    111 
    112 class VariableIndentationOutputStream {
    113  public:
    114   explicit VariableIndentationOutputStream(std::ostream* os, char text = kIndentChar)
    115       : indenter_(os->rdbuf(), text, 0u),
    116         indented_os_(&indenter_) {
    117   }
    118 
    119   std::ostream& Stream() {
    120     return indented_os_;
    121   }
    122 
    123   void IncreaseIndentation(size_t adjustment) {
    124     indenter_.count_ += adjustment;
    125   }
    126 
    127   void DecreaseIndentation(size_t adjustment) {
    128     DCHECK_GE(indenter_.count_, adjustment);
    129     indenter_.count_ -= adjustment;
    130   }
    131 
    132  private:
    133   Indenter indenter_;
    134   std::ostream indented_os_;
    135 
    136   DISALLOW_COPY_AND_ASSIGN(VariableIndentationOutputStream);
    137 };
    138 
    139 class ScopedIndentation {
    140  public:
    141   explicit ScopedIndentation(VariableIndentationOutputStream* vios,
    142                              size_t adjustment = kIndentBy1Count)
    143       : vios_(vios),
    144         adjustment_(adjustment) {
    145     vios_->IncreaseIndentation(adjustment_);
    146   }
    147 
    148   ~ScopedIndentation() {
    149     vios_->DecreaseIndentation(adjustment_);
    150   }
    151 
    152  private:
    153   VariableIndentationOutputStream* const vios_;
    154   const size_t adjustment_;
    155 
    156   DISALLOW_COPY_AND_ASSIGN(ScopedIndentation);
    157 };
    158 
    159 }  // namespace art
    160 
    161 #endif  // ART_RUNTIME_INDENTER_H_
    162