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:
Indenter(std::streambuf * out,char text,size_t count)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:
xsputn(const char * s,std::streamsize n)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 
overflow(int_type c)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 
sync()66   int sync() {
67     return out_sbuf_->pubsync();
68   }
69 
Write(const char * s,std::streamsize n)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 
RawWrite(const char * s,std::streamsize n)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 
Stream()119   std::ostream& Stream() {
120     return indented_os_;
121   }
122 
IncreaseIndentation(size_t adjustment)123   void IncreaseIndentation(size_t adjustment) {
124     indenter_.count_ += adjustment;
125   }
126 
DecreaseIndentation(size_t adjustment)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)
vios_(vios)143       : vios_(vios),
144         adjustment_(adjustment) {
145     vios_->IncreaseIndentation(adjustment_);
146   }
147 
~ScopedIndentation()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