// Copyright (c) 2014-2018 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #ifndef TAO_PEGTL_SRC_EXAMPLES_PEGTL_JSON_CLASSES_HPP // NOLINT #define TAO_PEGTL_SRC_EXAMPLES_PEGTL_JSON_CLASSES_HPP #include #include #include #include #include namespace examples { enum class json_type { ARRAY, BOOLEAN, NULL_, NUMBER, OBJECT, STRING }; class json_base { protected: explicit json_base( const json_type in_type ) : type( in_type ) { } virtual ~json_base() = default; public: json_base( const json_base& ) = delete; json_base( json_base&& ) = delete; void operator=( const json_base& ) = delete; void operator=( json_base&& ) = delete; virtual void stream( std::ostream& ) const = 0; const json_type type; }; inline std::ostream& operator<<( std::ostream& o, const json_base& j ) { j.stream( o ); return o; } inline std::ostream& operator<<( std::ostream& o, const std::shared_ptr< json_base >& j ) { return j ? ( o << *j ) : ( o << "NULL" ); } struct array_json : public json_base { array_json() : json_base( json_type::ARRAY ) { } std::vector< std::shared_ptr< json_base > > data; void stream( std::ostream& o ) const override { o << '['; if( !data.empty() ) { auto iter = data.begin(); o << *iter; while( ++iter != data.end() ) { o << ',' << *iter; } } o << ']'; } }; struct boolean_json : public json_base { explicit boolean_json( const bool in_data ) : json_base( json_type::BOOLEAN ), data( in_data ) { } bool data; void stream( std::ostream& o ) const override { o << ( data ? "true" : "false" ); } }; struct null_json : public json_base { null_json() : json_base( json_type::NULL_ ) { } void stream( std::ostream& o ) const override { o << "null"; } }; struct number_json : public json_base { explicit number_json( const long double in_data ) : json_base( json_type::NUMBER ), data( in_data ) { } long double data; void stream( std::ostream& o ) const override { o << data; } }; inline std::string json_escape( const std::string& data ) { std::string r = "\""; r.reserve( data.size() + 4 ); static const char* h = "0123456789abcdef"; const auto* d = static_cast< const unsigned char* >( static_cast< const void* >( data.data() ) ); for( std::size_t i = 0; i < data.size(); ++i ) { switch( const auto c = d[ i ] ) { case '\b': r += "\\b"; break; case '\f': r += "\\f"; break; case '\n': r += "\\n"; break; case '\r': r += "\\r"; break; case '\t': r += "\\t"; break; case '\\': r += "\\\\"; break; case '\"': r += "\\\""; break; default: if( ( c < 32 ) || ( c == 127 ) ) { r += "\\u00"; r += h[ ( c & 0xf0 ) >> 4 ]; r += h[ c & 0x0f ]; continue; } r += c; // Assume valid UTF-8. break; } } r += '"'; return r; } struct string_json : public json_base { explicit string_json( const std::string& in_data ) // NOLINT : json_base( json_type::STRING ), data( in_data ) { } std::string data; void stream( std::ostream& o ) const override { o << json_escape( data ); } }; struct object_json : public json_base { object_json() : json_base( json_type::OBJECT ) { } std::map< std::string, std::shared_ptr< json_base > > data; void stream( std::ostream& o ) const override { o << '{'; if( !data.empty() ) { auto iter = data.begin(); o << json_escape( iter->first ) << ':' << iter->second; while( ++iter != data.end() ) { o << ',' << json_escape( iter->first ) << ':' << iter->second; } } o << '}'; } }; } // namespace examples #endif