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