1*a03ca8b9SKrzysztof Kosiński // Copyright 2017 The Chromium Authors. All rights reserved. 2*a03ca8b9SKrzysztof Kosiński // Use of this source code is governed by a BSD-style license that can be 3*a03ca8b9SKrzysztof Kosiński // found in the LICENSE file. 4*a03ca8b9SKrzysztof Kosiński 5*a03ca8b9SKrzysztof Kosiński #ifndef COMPONENTS_ZUCCHINI_IO_UTILS_H_ 6*a03ca8b9SKrzysztof Kosiński #define COMPONENTS_ZUCCHINI_IO_UTILS_H_ 7*a03ca8b9SKrzysztof Kosiński 8*a03ca8b9SKrzysztof Kosiński #include <stdint.h> 9*a03ca8b9SKrzysztof Kosiński 10*a03ca8b9SKrzysztof Kosiński #include <cctype> 11*a03ca8b9SKrzysztof Kosiński #include <istream> 12*a03ca8b9SKrzysztof Kosiński #include <ostream> 13*a03ca8b9SKrzysztof Kosiński #include <sstream> 14*a03ca8b9SKrzysztof Kosiński #include <string> 15*a03ca8b9SKrzysztof Kosiński 16*a03ca8b9SKrzysztof Kosiński namespace zucchini { 17*a03ca8b9SKrzysztof Kosiński 18*a03ca8b9SKrzysztof Kosiński // An std::ostream wrapper that that limits number of std::endl lines to output, 19*a03ca8b9SKrzysztof Kosiński // useful for preventing excessive debug message output. Usage requires some 20*a03ca8b9SKrzysztof Kosiński // work by the caller. Sample: 21*a03ca8b9SKrzysztof Kosiński // static LimitedOutputStream los(std::cerr, 10); 22*a03ca8b9SKrzysztof Kosiński // if (!los.full()) { 23*a03ca8b9SKrzysztof Kosiński // ... // Prepare message. Block may be skipped so don't do other work! 24*a03ca8b9SKrzysztof Kosiński // los << message; 25*a03ca8b9SKrzysztof Kosiński // los << std::endl; // Important! 26*a03ca8b9SKrzysztof Kosiński // } 27*a03ca8b9SKrzysztof Kosiński class LimitedOutputStream : public std::ostream { 28*a03ca8b9SKrzysztof Kosiński private: 29*a03ca8b9SKrzysztof Kosiński class StreamBuf : public std::stringbuf { 30*a03ca8b9SKrzysztof Kosiński public: 31*a03ca8b9SKrzysztof Kosiński StreamBuf(std::ostream& os, int limit); 32*a03ca8b9SKrzysztof Kosiński ~StreamBuf() override; 33*a03ca8b9SKrzysztof Kosiński 34*a03ca8b9SKrzysztof Kosiński int sync() override; full()35*a03ca8b9SKrzysztof Kosiński bool full() const { return counter_ >= limit_; } 36*a03ca8b9SKrzysztof Kosiński 37*a03ca8b9SKrzysztof Kosiński private: 38*a03ca8b9SKrzysztof Kosiński std::ostream& os_; 39*a03ca8b9SKrzysztof Kosiński const int limit_; 40*a03ca8b9SKrzysztof Kosiński int counter_ = 0; 41*a03ca8b9SKrzysztof Kosiński }; 42*a03ca8b9SKrzysztof Kosiński 43*a03ca8b9SKrzysztof Kosiński public: 44*a03ca8b9SKrzysztof Kosiński LimitedOutputStream(std::ostream& os, int limit); 45*a03ca8b9SKrzysztof Kosiński LimitedOutputStream(const LimitedOutputStream&) = delete; 46*a03ca8b9SKrzysztof Kosiński const LimitedOutputStream& operator=(const LimitedOutputStream&) = delete; full()47*a03ca8b9SKrzysztof Kosiński bool full() const { return buf_.full(); } 48*a03ca8b9SKrzysztof Kosiński 49*a03ca8b9SKrzysztof Kosiński private: 50*a03ca8b9SKrzysztof Kosiński StreamBuf buf_; 51*a03ca8b9SKrzysztof Kosiński }; 52*a03ca8b9SKrzysztof Kosiński 53*a03ca8b9SKrzysztof Kosiński // A class to render hexadecimal numbers for std::ostream with 0-padding. This 54*a03ca8b9SKrzysztof Kosiński // is more concise and flexible than stateful STL manipulator alternatives; so: 55*a03ca8b9SKrzysztof Kosiński // std::ios old_fmt(nullptr); 56*a03ca8b9SKrzysztof Kosiński // old_fmt.copyfmt(std::cout); 57*a03ca8b9SKrzysztof Kosiński // std::cout << std::uppercase << std::hex; 58*a03ca8b9SKrzysztof Kosiński // std::cout << std::setfill('0') << std::setw(8) << int_data << std::endl; 59*a03ca8b9SKrzysztof Kosiński // std::cout.copyfmt(old_fmt); 60*a03ca8b9SKrzysztof Kosiński // can be expressed as: 61*a03ca8b9SKrzysztof Kosiński // std::cout << AxHex<8>(int_data) << std::endl; 62*a03ca8b9SKrzysztof Kosiński template <int N, typename T = uint32_t> 63*a03ca8b9SKrzysztof Kosiński struct AsHex { AsHexAsHex64*a03ca8b9SKrzysztof Kosiński explicit AsHex(T value_in) : value(value_in) {} 65*a03ca8b9SKrzysztof Kosiński T value; 66*a03ca8b9SKrzysztof Kosiński }; 67*a03ca8b9SKrzysztof Kosiński 68*a03ca8b9SKrzysztof Kosiński template <int N, typename T> 69*a03ca8b9SKrzysztof Kosiński std::ostream& operator<<(std::ostream& os, const AsHex<N, T>& as_hex) { 70*a03ca8b9SKrzysztof Kosiński char buf[N + 1]; 71*a03ca8b9SKrzysztof Kosiński buf[N] = '\0'; 72*a03ca8b9SKrzysztof Kosiński T value = as_hex.value; 73*a03ca8b9SKrzysztof Kosiński for (int i = N - 1; i >= 0; --i, value >>= 4) 74*a03ca8b9SKrzysztof Kosiński buf[i] = "0123456789ABCDEF"[static_cast<int>(value & 0x0F)]; 75*a03ca8b9SKrzysztof Kosiński if (value) 76*a03ca8b9SKrzysztof Kosiński os << "..."; // To indicate data truncation, or negative values. 77*a03ca8b9SKrzysztof Kosiński os << buf; 78*a03ca8b9SKrzysztof Kosiński return os; 79*a03ca8b9SKrzysztof Kosiński } 80*a03ca8b9SKrzysztof Kosiński 81*a03ca8b9SKrzysztof Kosiński // An output manipulator to simplify printing list separators. Sample usage: 82*a03ca8b9SKrzysztof Kosiński // PrefixSep sep(","); 83*a03ca8b9SKrzysztof Kosiński // for (int i : {3, 1, 4, 1, 5, 9}) 84*a03ca8b9SKrzysztof Kosiński // std::cout << sep << i; 85*a03ca8b9SKrzysztof Kosiński // std::cout << std::endl; // Outputs "3,1,4,1,5,9\n". 86*a03ca8b9SKrzysztof Kosiński class PrefixSep { 87*a03ca8b9SKrzysztof Kosiński public: PrefixSep(const std::string & sep_str)88*a03ca8b9SKrzysztof Kosiński explicit PrefixSep(const std::string& sep_str) : sep_str_(sep_str) {} 89*a03ca8b9SKrzysztof Kosiński PrefixSep(const PrefixSep&) = delete; 90*a03ca8b9SKrzysztof Kosiński const PrefixSep& operator=(const PrefixSep&) = delete; 91*a03ca8b9SKrzysztof Kosiński 92*a03ca8b9SKrzysztof Kosiński friend std::ostream& operator<<(std::ostream& ostr, PrefixSep& obj); 93*a03ca8b9SKrzysztof Kosiński 94*a03ca8b9SKrzysztof Kosiński private: 95*a03ca8b9SKrzysztof Kosiński std::string sep_str_; 96*a03ca8b9SKrzysztof Kosiński bool first_ = true; 97*a03ca8b9SKrzysztof Kosiński }; 98*a03ca8b9SKrzysztof Kosiński 99*a03ca8b9SKrzysztof Kosiński // An input manipulator that dictates the expected next character in 100*a03ca8b9SKrzysztof Kosiński // |std::istream|, and invalidates the stream if expectation is not met. 101*a03ca8b9SKrzysztof Kosiński class EatChar { 102*a03ca8b9SKrzysztof Kosiński public: EatChar(char ch)103*a03ca8b9SKrzysztof Kosiński explicit EatChar(char ch) : ch_(ch) {} 104*a03ca8b9SKrzysztof Kosiński EatChar(const EatChar&) = delete; 105*a03ca8b9SKrzysztof Kosiński const EatChar& operator=(const EatChar&) = delete; 106*a03ca8b9SKrzysztof Kosiński 107*a03ca8b9SKrzysztof Kosiński friend inline std::istream& operator>>(std::istream& istr, 108*a03ca8b9SKrzysztof Kosiński const EatChar& obj) { 109*a03ca8b9SKrzysztof Kosiński if (!istr.fail() && istr.get() != obj.ch_) 110*a03ca8b9SKrzysztof Kosiński istr.setstate(std::ios_base::failbit); 111*a03ca8b9SKrzysztof Kosiński return istr; 112*a03ca8b9SKrzysztof Kosiński } 113*a03ca8b9SKrzysztof Kosiński 114*a03ca8b9SKrzysztof Kosiński private: 115*a03ca8b9SKrzysztof Kosiński char ch_; 116*a03ca8b9SKrzysztof Kosiński }; 117*a03ca8b9SKrzysztof Kosiński 118*a03ca8b9SKrzysztof Kosiński // An input manipulator that reads an unsigned integer from |std::istream|, 119*a03ca8b9SKrzysztof Kosiński // and invalidates the stream on failure. Intolerant of leading white spaces, 120*a03ca8b9SKrzysztof Kosiński template <typename T> 121*a03ca8b9SKrzysztof Kosiński class StrictUInt { 122*a03ca8b9SKrzysztof Kosiński public: StrictUInt(T & var)123*a03ca8b9SKrzysztof Kosiński explicit StrictUInt(T& var) : var_(var) {} 124*a03ca8b9SKrzysztof Kosiński StrictUInt(const StrictUInt&) = default; 125*a03ca8b9SKrzysztof Kosiński 126*a03ca8b9SKrzysztof Kosiński friend std::istream& operator>>(std::istream& istr, StrictUInt<T> obj) { 127*a03ca8b9SKrzysztof Kosiński if (!istr.fail() && !::isdigit(istr.peek())) { 128*a03ca8b9SKrzysztof Kosiński istr.setstate(std::ios_base::failbit); 129*a03ca8b9SKrzysztof Kosiński return istr; 130*a03ca8b9SKrzysztof Kosiński } 131*a03ca8b9SKrzysztof Kosiński return istr >> obj.var_; 132*a03ca8b9SKrzysztof Kosiński } 133*a03ca8b9SKrzysztof Kosiński 134*a03ca8b9SKrzysztof Kosiński private: 135*a03ca8b9SKrzysztof Kosiński T& var_; 136*a03ca8b9SKrzysztof Kosiński }; 137*a03ca8b9SKrzysztof Kosiński 138*a03ca8b9SKrzysztof Kosiński // Stub out uint8_t: istream treats it as char, and value won't be read as int! 139*a03ca8b9SKrzysztof Kosiński template <> 140*a03ca8b9SKrzysztof Kosiński struct StrictUInt<uint8_t> {}; 141*a03ca8b9SKrzysztof Kosiński 142*a03ca8b9SKrzysztof Kosiński } // namespace zucchini 143*a03ca8b9SKrzysztof Kosiński 144*a03ca8b9SKrzysztof Kosiński #endif // COMPONENTS_ZUCCHINI_IO_UTILS_H_ 145