• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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