xref: /aosp_15_r20/external/zucchini/io_utils.h (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
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