/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_LIBARTBASE_BASE_INDENTER_H_ #define ART_LIBARTBASE_BASE_INDENTER_H_ #include <ostream> #include <streambuf> #include <android-base/logging.h> #include "macros.h" namespace art { constexpr char kIndentChar =' '; constexpr size_t kIndentBy1Count = 2; class Indenter : public std::streambuf { public: Indenter(std::streambuf* out, char text, size_t count) : indent_next_(true), out_sbuf_(out), text_{text, text, text, text, text, text, text, text}, count_(count) {} private: std::streamsize xsputn(const char* s, std::streamsize n) override { std::streamsize result = n; // Aborts on failure. const char* eol = static_cast<const char*>(memchr(s, '\n', n)); while (eol != nullptr) { size_t to_write = eol + 1 - s; Write(s, to_write); s += to_write; n -= to_write; indent_next_ = true; eol = static_cast<const char*>(memchr(s, '\n', n)); } if (n != 0u) { Write(s, n); } return result; } int_type overflow(int_type c) override { if (UNLIKELY(c == std::char_traits<char>::eof())) { out_sbuf_->pubsync(); return c; } char data[1] = { static_cast<char>(c) }; Write(data, 1u); indent_next_ = (c == '\n'); return c; } int sync() override { return out_sbuf_->pubsync(); } void Write(const char* s, std::streamsize n) { if (indent_next_) { size_t remaining = count_; while (remaining != 0u) { size_t to_write = std::min(remaining, sizeof(text_)); RawWrite(text_, to_write); remaining -= to_write; } indent_next_ = false; } RawWrite(s, n); } void RawWrite(const char* s, std::streamsize n) { size_t written = out_sbuf_->sputn(s, n); s += written; n -= written; while (n != 0u) { out_sbuf_->pubsync(); written = out_sbuf_->sputn(s, n); CHECK_NE(written, 0u) << "Error writing to buffer. Disk full?"; s += written; n -= written; } } bool indent_next_; // Buffer to write output to. std::streambuf* const out_sbuf_; // Text output as indent. const char text_[8]; // Number of times text is output. size_t count_; friend class VariableIndentationOutputStream; DISALLOW_COPY_AND_ASSIGN(Indenter); }; class VariableIndentationOutputStream { public: explicit VariableIndentationOutputStream(std::ostream* os, char text = kIndentChar) : indenter_(os->rdbuf(), text, 0u), indented_os_(&indenter_) { } std::ostream& Stream() { return indented_os_; } size_t GetIndentation() const { return indenter_.count_; } void IncreaseIndentation(size_t adjustment) { indenter_.count_ += adjustment; } void DecreaseIndentation(size_t adjustment) { DCHECK_GE(indenter_.count_, adjustment); indenter_.count_ -= adjustment; } private: Indenter indenter_; std::ostream indented_os_; DISALLOW_COPY_AND_ASSIGN(VariableIndentationOutputStream); }; class ScopedIndentation { public: explicit ScopedIndentation(VariableIndentationOutputStream* vios, size_t adjustment = kIndentBy1Count) : vios_(vios), adjustment_(adjustment) { vios_->IncreaseIndentation(adjustment_); } ~ScopedIndentation() { vios_->DecreaseIndentation(adjustment_); } private: VariableIndentationOutputStream* const vios_; const size_t adjustment_; DISALLOW_COPY_AND_ASSIGN(ScopedIndentation); }; } // namespace art #endif // ART_LIBARTBASE_BASE_INDENTER_H_