// Copyright 2019 Hans Dembinski // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_HISTOGRAM_DETAIL_COUNTING_STREAMBUF_HPP #define BOOST_HISTOGRAM_DETAIL_COUNTING_STREAMBUF_HPP #include #include #include namespace boost { namespace histogram { namespace detail { // detect how many characters will be printed by formatted output template > struct counting_streambuf : std::basic_streambuf { using base_t = std::basic_streambuf; using typename base_t::char_type; using typename base_t::int_type; std::streamsize* p_count; counting_streambuf(std::streamsize& c) : p_count(&c) {} std::streamsize xsputn(const char_type* /* s */, std::streamsize n) override { *p_count += n; return n; } int_type overflow(int_type ch) override { ++*p_count; return ch; } }; template struct count_guard { using bos = std::basic_ostream; using bsb = std::basic_streambuf; counting_streambuf csb; bos* p_os; bsb* p_rdbuf; count_guard(bos& os, std::streamsize& s) : csb(s), p_os(&os), p_rdbuf(os.rdbuf(&csb)) {} count_guard(count_guard&& o) : csb(o.csb), p_os(boost::exchange(o.p_os, nullptr)), p_rdbuf(o.p_rdbuf) {} count_guard& operator=(count_guard&& o) { if (this != &o) { csb = std::move(o.csb); p_os = boost::exchange(o.p_os, nullptr); p_rdbuf = o.p_rdbuf; } return *this; } ~count_guard() { if (p_os) p_os->rdbuf(p_rdbuf); } }; template count_guard make_count_guard(std::basic_ostream& os, std::streamsize& s) { return {os, s}; } } // namespace detail } // namespace histogram } // namespace boost #endif