Click here to Skip to main content
15,880,967 members
Articles / Web Development / HTML

JSON Spirit: A C++ JSON Parser/Generator Implemented with Boost Spirit

Rate me:
Please Sign up or sign in to vote.
4.92/5 (110 votes)
10 May 2014MIT12 min read 4.1M   24.3K   287  
A C++ JSON parser/generator written using Boost::spirit
#ifndef JASON_SPIRIT_VALUE
#define JASON_SPIRIT_VALUE

/* Copyright (c) 2007-2009 John W Wilkinson

   This source code can be used for any purpose as long as
   this comment is retained. */

// json spirit version 4.00

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

#include <vector>
#include <map>
#include <string>
#include <cassert>
#include <boost/config.hpp> 
#include <boost/cstdint.hpp> 
#include <boost/shared_ptr.hpp> 

namespace json_spirit
{
    enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type };

    template< class Config >    // Config determines whether the value uses std::string or std::wstring and
                                // whether JSON Objects are represented as vectors or maps
    class Value_impl
    {
    public:

        typedef Config Config_type;
        typedef typename Config::String_type String_type;
        typedef typename Config::Object_type Object;
        typedef typename Config::Array_type Array;
        typedef typename String_type::const_pointer Const_str_ptr;  // eg const char*

        Value_impl();  // creates null value
        Value_impl( Const_str_ptr      value ); 
        Value_impl( const String_type& value );
        Value_impl( const Object&      value );
        Value_impl( const Array&       value );
        Value_impl( bool               value );
        Value_impl( int                value );
        Value_impl( boost::int64_t     value );
        Value_impl( boost::uint64_t    value );
        Value_impl( double             value );

        Value_impl( const Value_impl& other );

        bool operator==( const Value_impl& lhs ) const;

        Value_impl& operator=( const Value_impl& lhs );

        Value_type type() const;

        bool is_uint64() const;
        bool is_null() const;

        const String_type& get_str()    const;
        const Object&      get_obj()    const;
        const Array&       get_array()  const;
        bool               get_bool()   const;
        int                get_int()    const;
        boost::int64_t     get_int64()  const;
        boost::uint64_t    get_uint64() const;
        double             get_real()   const;

        Object& get_obj();
        Array&  get_array();

        template< typename T > T get_value() const;  // example usage: int    i = value.get_value< int >();
                                                     // or             double d = value.get_value< double >();

        static const Value_impl null;

    private:

        Value_type type_;

        typedef boost::shared_ptr< Object > Object_ptr;
        typedef boost::shared_ptr< Array > Array_ptr;

        String_type str_;
        Object_ptr obj_p_;
        Array_ptr array_p_;
        union
        {
           bool bool_;
           boost::int64_t i_;
           double d_;
        };
        bool is_uint64_;
    };

    // vector objects

    template< class Config >
    struct Pair_impl
    {
        typedef typename Config::String_type String_type;
        typedef typename Config::Value_type Value_type;

        Pair_impl( const String_type& name, const Value_type& value );

        bool operator==( const Pair_impl& lhs ) const;

        String_type name_;
        Value_type value_;
    };

    template< class String >
    struct Config_vector
    {
        typedef String String_type;
        typedef Value_impl< Config_vector > Value_type;
        typedef Pair_impl < Config_vector > Pair_type;
        typedef std::vector< Value_type > Array_type;
        typedef std::vector< Pair_type > Object_type;

        static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value )
        {
            obj.push_back( Pair_type( name , value ) );

            return obj.back().value_;
        }
                
        static String_type get_name( const Pair_type& pair )
        {
            return pair.name_;
        }
                
        static Value_type get_value( const Pair_type& pair )
        {
            return pair.value_;
        }
    };

    // typedefs for ASCII

    typedef Config_vector< std::string > Config;

    typedef Config::Value_type  Value;
    typedef Config::Pair_type   Pair;
    typedef Config::Object_type Object;
    typedef Config::Array_type  Array;

    // typedefs for Unicode

#ifndef BOOST_NO_STD_WSTRING

    typedef Config_vector< std::wstring > wConfig;

    typedef wConfig::Value_type  wValue;
    typedef wConfig::Pair_type   wPair;
    typedef wConfig::Object_type wObject;
    typedef wConfig::Array_type  wArray;
#endif

    // map objects

    template< class String >
    struct Config_map
    {
        typedef String String_type;
        typedef Value_impl< Config_map > Value_type;
        typedef std::vector< Value_type > Array_type;
        typedef std::map< String_type, Value_type > Object_type;
        typedef typename Object_type::value_type Pair_type;

        static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value )
        {
            return obj[ name ] = value;
        }
                
        static String_type get_name( const Pair_type& pair )
        {
            return pair.first;
        }
                
        static Value_type get_value( const Pair_type& pair )
        {
            return pair.second;
        }
    };

    // typedefs for ASCII

    typedef Config_map< std::string > mConfig;

    typedef mConfig::Value_type  mValue;
    typedef mConfig::Object_type mObject;
    typedef mConfig::Array_type  mArray;

    // typedefs for Unicode

#ifndef BOOST_NO_STD_WSTRING

    typedef Config_map< std::wstring > wmConfig;

    typedef wmConfig::Value_type  wmValue;
    typedef wmConfig::Object_type wmObject;
    typedef wmConfig::Array_type  wmArray;

#endif

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //
    // implementation

    template< class Config >
    const Value_impl< Config > Value_impl< Config >::null;

    template< class Config >
    Value_impl< Config >::Value_impl()
    :   type_( null_type )
    ,   is_uint64_( false )
    {
    }

    template< class Config >
    Value_impl< Config >::Value_impl( const Const_str_ptr value )
    :   type_( str_type )
    ,   str_( value )
    ,   is_uint64_( false )
    {
    }

    template< class Config >
    Value_impl< Config >::Value_impl( const String_type& value )
    :   type_( str_type )
    ,   str_( value )
    ,   is_uint64_( false )
    {
    }

    template< class Config >
    Value_impl< Config >::Value_impl( const Object& value )
    :   type_( obj_type )
    ,   obj_p_( new Object( value ) )
    ,   is_uint64_( false )
    {
    }

    template< class Config >
    Value_impl< Config >::Value_impl( const Array& value )
    :   type_( array_type )
    ,   array_p_( new Array( value ) )
    ,   is_uint64_( false )
    {
    }

    template< class Config >
    Value_impl< Config >::Value_impl( bool value )
    :   type_( bool_type )
    ,   bool_( value )
    ,   is_uint64_( false )
    {
    }

    template< class Config >
    Value_impl< Config >::Value_impl( int value )
    :   type_( int_type )
    ,   i_( value )
    ,   is_uint64_( false )
    {
    }

    template< class Config >
    Value_impl< Config >::Value_impl( boost::int64_t value )
    :   type_( int_type )
    ,   i_( value )
    ,   is_uint64_( false )
    {
    }

    template< class Config >
    Value_impl< Config >::Value_impl( boost::uint64_t value )
    :   type_( int_type )
    ,   i_( static_cast< boost::int64_t >( value ) )
    ,   is_uint64_( true )
    {
    }

    template< class Config >
    Value_impl< Config >::Value_impl( double value )
    :   type_( real_type )
    ,   d_( value )
    ,   is_uint64_( false )
    {
    }

    template< class Config >
    Value_impl< Config >::Value_impl( const Value_impl< Config >& other )
    :   type_( other.type() )
    ,   is_uint64_( other.is_uint64_ )
    {
        switch( type_ )
        {
            case str_type:   str_     = other.get_str();                               break;
            case obj_type:   obj_p_   = Object_ptr( new Object( other.get_obj() ) );   break;
            case array_type: array_p_ = Array_ptr ( new Array ( other.get_array() ) ); break;
            case bool_type:  bool_    = other.get_bool();                              break;
            case int_type:   i_       = other.get_int64();                             break;
            case real_type:  d_       = other.get_real();                              break;
            case null_type:                                                            break;
            default: assert( false );
        };
    }

    template< class Config >
    Value_impl< Config >& Value_impl< Config >::operator=( const Value_impl& lhs )
    {
        Value_impl tmp( lhs );

        std::swap( type_, tmp.type_ );
        str_    .swap( tmp.str_ );
        obj_p_  .swap( tmp.obj_p_ );
        array_p_.swap( tmp.array_p_ );
        std::swap( is_uint64_, tmp.is_uint64_ );

        switch( type_ )
        {
            case bool_type:  std::swap( bool_,      tmp.bool_ );      break;
            case int_type:   std::swap( i_,         tmp.i_ );         break;
            case real_type:  std::swap( d_,         tmp.d_ );         break;
        };

        return *this;
    }

    template< class Config >
    bool Value_impl< Config >::operator==( const Value_impl& lhs ) const
    {
        if( this == &lhs ) return true;

        if( type() != lhs.type() ) return false;

        switch( type_ )
        {
            case str_type:   return get_str()   == lhs.get_str();
            case obj_type:   return get_obj()   == lhs.get_obj();
            case array_type: return get_array() == lhs.get_array();
            case bool_type:  return get_bool()  == lhs.get_bool();
            case int_type:   return ( get_int64() == lhs.get_int64() ) &&
                                    ( is_uint64() == lhs.is_uint64() );
            case real_type:  return get_real()  == lhs.get_real();
            case null_type:  return true;
        };

        assert( false );

        return false; 
    }

    template< class Config >
    Value_type Value_impl< Config >::type() const
    {
        return type_;
    }

    template< class Config >
    bool Value_impl< Config >::is_uint64() const
    {
        return is_uint64_;
    }

    template< class Config >
    bool Value_impl< Config >::is_null() const
    {
        return type() == null_type;
    }

    template< class Config >
    const typename Config::String_type& Value_impl< Config >::get_str() const
    {
        assert( type() == str_type );

        return str_;
    }

    template< class Config >
    const typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() const
    {
        assert( type() == obj_type );

        return *obj_p_;
    }
     
    template< class Config >
    const typename Value_impl< Config >::Array& Value_impl< Config >::get_array() const
    {
        assert( type() == array_type );

        return *array_p_;
    }
     
    template< class Config >
    bool Value_impl< Config >::get_bool() const
    {
        assert( type() == bool_type );

        return bool_;
    }
     
    template< class Config >
    int Value_impl< Config >::get_int() const
    {
        assert( type() == int_type );

        return static_cast< int >( i_ );
    }
    
    template< class Config >
    boost::int64_t Value_impl< Config >::get_int64() const
    {
        assert( type() == int_type );

        return i_;
    }
    
    template< class Config >
    boost::uint64_t Value_impl< Config >::get_uint64() const
    {
        assert( type() == int_type );

        return static_cast< boost::uint64_t >( i_ );
    }

    template< class Config >
    double Value_impl< Config >::get_real() const
    {
        if( type() == int_type )
        {
            return is_uint64() ? static_cast< double >( get_uint64() )
                               : static_cast< double >( get_int64() );
        }

        assert( type() == real_type );

        return d_;
    }

    template< class Config >
    typename Value_impl< Config >::Object& Value_impl< Config >::get_obj()
    {
        assert( type() == obj_type );

        return *obj_p_;
    }

    template< class Config >
    typename Value_impl< Config >::Array& Value_impl< Config >::get_array()
    {
        assert( type() == array_type );

        return *array_p_;
    }

    template< class Config >
    Pair_impl< Config >::Pair_impl( const String_type& name, const Value_type& value )
    :   name_( name )
    ,   value_( value )
    {
    }

    template< class Config >
    bool Pair_impl< Config >::operator==( const Pair_impl< Config >& lhs ) const
    {
        if( this == &lhs ) return true;

        return ( name_ == lhs.name_ ) && ( value_ == lhs.value_ );
    }

    // converts a C string, ie. 8 bit char array, to a string object
    //
    template < class String_type >
    String_type to_str( const char* c_str )
    {
        String_type result;

        for( const char* p = c_str; *p != 0; ++p )
        {
            result += *p;
        }

        return result;
    }

    //

    namespace internal_
    {
        template< typename T >
        struct Type_to_type
        {
        };

        template< class Value > 
        int get_value( const Value& value, Type_to_type< int > )
        {
            return value.get_int();
        }
       
        template< class Value > 
        boost::int64_t get_value( const Value& value, Type_to_type< boost::int64_t > )
        {
            return value.get_int64();
        }
       
        template< class Value > 
        boost::uint64_t get_value( const Value& value, Type_to_type< boost::uint64_t > )
        {
            return value.get_uint64();
        }
       
        template< class Value > 
        double get_value( const Value& value, Type_to_type< double > )
        {
            return value.get_real();
        }
       
        template< class Value > 
        typename Value::String_type get_value( const Value& value, Type_to_type< typename Value::String_type > )
        {
            return value.get_str();
        }
       
        template< class Value > 
        typename Value::Array get_value( const Value& value, Type_to_type< typename Value::Array > )
        {
            return value.get_array();
        }
       
        template< class Value > 
        typename Value::Object get_value( const Value& value, Type_to_type< typename Value::Object > )
        {
            return value.get_obj();
        }
       
        template< class Value > 
        bool get_value( const Value& value, Type_to_type< bool > )
        {
            return value.get_bool();
        }
    }

    template< class Config >
    template< typename T > 
    T Value_impl< Config >::get_value() const
    {
        return internal_::get_value( *this, internal_::Type_to_type< T >() );
    }
}

#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer (Senior) Spirent Communications Plc
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions