xref: /aosp_15_r20/art/libartbase/base/indenter.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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