counting_streambuf.hpp 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. // Copyright 2019 Hans Dembinski
  2. //
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_HISTOGRAM_DETAIL_COUNTING_STREAMBUF_HPP
  7. #define BOOST_HISTOGRAM_DETAIL_COUNTING_STREAMBUF_HPP
  8. #include <boost/core/exchange.hpp>
  9. #include <ostream>
  10. #include <streambuf>
  11. namespace boost {
  12. namespace histogram {
  13. namespace detail {
  14. // detect how many characters will be printed by formatted output
  15. template <class CharT, class Traits = std::char_traits<CharT>>
  16. struct counting_streambuf : std::basic_streambuf<CharT, Traits> {
  17. using base_t = std::basic_streambuf<CharT, Traits>;
  18. using typename base_t::char_type;
  19. using typename base_t::int_type;
  20. std::streamsize* p_count;
  21. counting_streambuf(std::streamsize& c) : p_count(&c) {}
  22. std::streamsize xsputn(const char_type* /* s */, std::streamsize n) override {
  23. *p_count += n;
  24. return n;
  25. }
  26. int_type overflow(int_type ch) override {
  27. ++*p_count;
  28. return ch;
  29. }
  30. };
  31. template <class C, class T>
  32. struct count_guard {
  33. using bos = std::basic_ostream<C, T>;
  34. using bsb = std::basic_streambuf<C, T>;
  35. counting_streambuf<C, T> csb;
  36. bos* p_os;
  37. bsb* p_rdbuf;
  38. count_guard(bos& os, std::streamsize& s) : csb(s), p_os(&os), p_rdbuf(os.rdbuf(&csb)) {}
  39. count_guard(count_guard&& o)
  40. : csb(o.csb), p_os(boost::exchange(o.p_os, nullptr)), p_rdbuf(o.p_rdbuf) {}
  41. count_guard& operator=(count_guard&& o) {
  42. if (this != &o) {
  43. csb = std::move(o.csb);
  44. p_os = boost::exchange(o.p_os, nullptr);
  45. p_rdbuf = o.p_rdbuf;
  46. }
  47. return *this;
  48. }
  49. ~count_guard() {
  50. if (p_os) p_os->rdbuf(p_rdbuf);
  51. }
  52. };
  53. template <class C, class T>
  54. count_guard<C, T> make_count_guard(std::basic_ostream<C, T>& os, std::streamsize& s) {
  55. return {os, s};
  56. }
  57. } // namespace detail
  58. } // namespace histogram
  59. } // namespace boost
  60. #endif