blob: 63eeec8ab85d3b6392ce64dd8653aaade419d274 [file] [log] [blame]
Samuel Huang06f1ae92018-03-13 18:19:34 +00001// 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
Samuel Huang06f1ae92018-03-13 18:19:34 +000016namespace 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// }
27class 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;
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);
Samuel Huangf137bf42021-08-13 15:42:26 +000045 LimitedOutputStream(const LimitedOutputStream&) = delete;
46 const LimitedOutputStream& operator=(const LimitedOutputStream&) = delete;
Samuel Huang06f1ae92018-03-13 18:19:34 +000047 bool full() const { return buf_.full(); }
48
49 private:
50 StreamBuf buf_;
Samuel Huang06f1ae92018-03-13 18:19:34 +000051};
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;
62template <int N, typename T = uint32_t>
63struct AsHex {
64 explicit AsHex(T value_in) : value(value_in) {}
65 T value;
66};
67
68template <int N, typename T>
69std::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".
86class PrefixSep {
87 public:
88 explicit PrefixSep(const std::string& sep_str) : sep_str_(sep_str) {}
Samuel Huangf137bf42021-08-13 15:42:26 +000089 PrefixSep(const PrefixSep&) = delete;
90 const PrefixSep& operator=(const PrefixSep&) = delete;
Samuel Huang06f1ae92018-03-13 18:19:34 +000091
92 friend std::ostream& operator<<(std::ostream& ostr, PrefixSep& obj);
93
94 private:
95 std::string sep_str_;
96 bool first_ = true;
Samuel Huang06f1ae92018-03-13 18:19:34 +000097};
98
99// An input manipulator that dictates the expected next character in
100// |std::istream|, and invalidates the stream if expectation is not met.
101class EatChar {
102 public:
103 explicit EatChar(char ch) : ch_(ch) {}
Samuel Huangf137bf42021-08-13 15:42:26 +0000104 EatChar(const EatChar&) = delete;
105 const EatChar& operator=(const EatChar&) = delete;
Samuel Huang06f1ae92018-03-13 18:19:34 +0000106
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_;
Samuel Huang06f1ae92018-03-13 18:19:34 +0000116};
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,
120template <typename T>
121class StrictUInt {
122 public:
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!
139template <>
140struct StrictUInt<uint8_t> {};
141
142} // namespace zucchini
143
144#endif // COMPONENTS_ZUCCHINI_IO_UTILS_H_