io_utils.h 4.1 KB

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