// 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 <iostream>
#include <map>
#include <memory>
#include <string>
#include <vector>
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