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