// Copyright (c) 2016-2022 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/json/ #ifndef TAO_JSON_EVENTS_TO_PRETTY_STREAM_HPP #define TAO_JSON_EVENTS_TO_PRETTY_STREAM_HPP #include #include #include #include #include #include #include #include #include #include #include "../binary_view.hpp" #include "../external/itoa.hpp" #include "../external/ryu.hpp" #include "../internal/escape.hpp" namespace tao::json::events { // Events consumer to build a JSON pretty string representation. class to_pretty_stream { protected: std::ostream& os; const std::size_t indent; std::string eol; bool first = true; bool after_key = true; void next() { if( !first ) { os.put( ',' ); } if( after_key ) { after_key = false; } else { os << eol; } } public: template< typename S > to_pretty_stream( std::ostream& in_os, const std::size_t in_indent, S&& in_eol ) : os( in_os ), indent( in_indent ), eol( std::forward< S >( in_eol ) ) {} to_pretty_stream( std::ostream& in_os, const std::size_t in_indent ) : to_pretty_stream( in_os, in_indent, "\n" ) {} void null() { next(); os.write( "null", 4 ); } void boolean( const bool v ) { next(); if( v ) { os.write( "true", 4 ); } else { os.write( "false", 5 ); } } void number( const std::int64_t v ) { next(); itoa::i64tos( os, v ); } void number( const std::uint64_t v ) { next(); itoa::u64tos( os, v ); } void number( const double v ) { next(); if( !std::isfinite( v ) ) { // if this throws, consider using non_finite_to_* transformers throw std::runtime_error( "non-finite double value invalid for JSON string representation" ); } ryu::d2s_stream( os, v ); } void string( const std::string_view v ) { next(); os.put( '"' ); internal::escape( os, v ); os.put( '"' ); } void binary( const tao::binary_view /*unused*/ ) // NOLINT(readability-convert-member-functions-to-static) { // if this throws, consider using binary_to_* transformers throw std::runtime_error( "binary data invalid for JSON string representation" ); } void begin_array( const std::size_t /*unused*/ = 0 ) { next(); os.put( '[' ); eol.resize( eol.size() + indent, os.fill() ); first = true; } void element() noexcept { first = false; } void end_array( const std::size_t /*unused*/ = 0 ) { eol.resize( eol.size() - indent ); if( !first ) { os << eol; } os.put( ']' ); } void begin_object( const std::size_t /*unused*/ = 0 ) { next(); os.put( '{' ); eol.resize( eol.size() + indent, os.fill() ); first = true; } void key( const std::string_view v ) { string( v ); os.write( ": ", 2 ); first = true; after_key = true; } void member() noexcept { first = false; } void end_object( const std::size_t /*unused*/ = 0 ) { eol.resize( eol.size() - indent ); if( !first ) { os << eol; } os.put( '}' ); } }; } // namespace tao::json::events #endif