diff --git a/json5_parser/json5_parser.h b/json5_parser/json5_parser.h index 1f84a48..2ba50c2 100644 --- a/json5_parser/json5_parser.h +++ b/json5_parser/json5_parser.h @@ -1,18 +1,18 @@ -#ifndef JSON_SPIRIT -#define JSON_SPIRIT - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json5_parser_value.h" -#include "json5_parser_reader.h" -#include "json5_parser_writer.h" -#include "json5_parser_utils.h" - -#endif +#ifndef JSON_SPIRIT +#define JSON_SPIRIT + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "json5_parser_reader.h" +#include "json5_parser_utils.h" +#include "json5_parser_value.h" +#include "json5_parser_writer.h" + +#endif diff --git a/json5_parser/json5_parser_error_position.h b/json5_parser/json5_parser_error_position.h index 6e0432d..749de77 100644 --- a/json5_parser/json5_parser_error_position.h +++ b/json5_parser/json5_parser_error_position.h @@ -1,54 +1,42 @@ -#ifndef JSON_SPIRIT_ERROR_POSITION -#define JSON_SPIRIT_ERROR_POSITION - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include - -namespace json5_parser -{ - // An Error_position exception is thrown by the "read_or_throw" functions below on finding an error. - // Note the "read_or_throw" functions are around 3 times slower than the standard functions "read" - // functions that return a bool. - // - struct Error_position - { - Error_position(); - Error_position( unsigned int line, unsigned int column, const std::string& reason ); - bool operator==( const Error_position& lhs ) const; - unsigned int line_; - unsigned int column_; - std::string reason_; - }; - - inline Error_position::Error_position() - : line_( 0 ) - , column_( 0 ) - { - } - - inline Error_position::Error_position( unsigned int line, unsigned int column, const std::string& reason ) - : line_( line ) - , column_( column ) - , reason_( reason ) - { - } - - inline bool Error_position::operator==( const Error_position& lhs ) const - { - if( this == &lhs ) return true; - - return ( reason_ == lhs.reason_ ) && - ( line_ == lhs.line_ ) && - ( column_ == lhs.column_ ); - } -} - -#endif +#ifndef JSON_SPIRIT_ERROR_POSITION +#define JSON_SPIRIT_ERROR_POSITION + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include + +namespace json5_parser { +// An Error_position exception is thrown by the "read_or_throw" functions below on +// finding an error. Note the "read_or_throw" functions are around 3 times slower than +// the standard functions "read" functions that return a bool. +// +struct Error_position { + Error_position(); + Error_position(unsigned int line, unsigned int column, const std::string& reason); + bool operator==(const Error_position& lhs) const; + unsigned int line_; + unsigned int column_; + std::string reason_; +}; + +inline Error_position::Error_position() : line_(0), column_(0) {} + +inline Error_position::Error_position(unsigned int line, unsigned int column, + const std::string& reason) + : line_(line), column_(column), reason_(reason) {} + +inline bool Error_position::operator==(const Error_position& lhs) const { + if (this == &lhs) return true; + + return (reason_ == lhs.reason_) && (line_ == lhs.line_) && (column_ == lhs.column_); +} +} // namespace json5_parser + +#endif diff --git a/json5_parser/json5_parser_reader.cpp b/json5_parser/json5_parser_reader.cpp index c6adb75..20d6e48 100644 --- a/json5_parser/json5_parser_reader.cpp +++ b/json5_parser/json5_parser_reader.cpp @@ -1,137 +1,121 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_reader.h" -#include "json5_parser_reader_template.h" - -using namespace json5_parser; - -#ifdef JSON_SPIRIT_VALUE_ENABLED - bool json5_parser::read( const std::string& s, Value& value ) - { - return read_string( s, value ); - } - - void json5_parser::read_or_throw( const std::string& s, Value& value ) - { - read_string_or_throw( s, value ); - } - - bool json5_parser::read( std::istream& is, Value& value ) - { - return read_stream( is, value ); - } - - void json5_parser::read_or_throw( std::istream& is, Value& value ) - { - read_stream_or_throw( is, value ); - } - - bool json5_parser::read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) - { - return read_range( begin, end, value ); - } - - void json5_parser::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) - { - begin = read_range_or_throw( begin, end, value ); - } -#endif - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - bool json5_parser::read( const std::wstring& s, wValue& value ) - { - return read_string( s, value ); - } - - void json5_parser::read_or_throw( const std::wstring& s, wValue& value ) - { - read_string_or_throw( s, value ); - } - - bool json5_parser::read( std::wistream& is, wValue& value ) - { - return read_stream( is, value ); - } - - void json5_parser::read_or_throw( std::wistream& is, wValue& value ) - { - read_stream_or_throw( is, value ); - } - - bool json5_parser::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) - { - return read_range( begin, end, value ); - } - - void json5_parser::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) - { - begin = read_range_or_throw( begin, end, value ); - } -#endif - -#ifdef JSON_SPIRIT_MVALUE_ENABLED - bool json5_parser::read( const std::string& s, mValue& value ) - { - return read_string( s, value ); - } - - void json5_parser::read_or_throw( const std::string& s, mValue& value ) - { - read_string_or_throw( s, value ); - } - - bool json5_parser::read( std::istream& is, mValue& value ) - { - return read_stream( is, value ); - } - - void json5_parser::read_or_throw( std::istream& is, mValue& value ) - { - read_stream_or_throw( is, value ); - } - - bool json5_parser::read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) - { - return read_range( begin, end, value ); - } - - void json5_parser::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) - { - begin = read_range_or_throw( begin, end, value ); - } -#endif - -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - bool json5_parser::read( const std::wstring& s, wmValue& value ) - { - return read_string( s, value ); - } - - void json5_parser::read_or_throw( const std::wstring& s, wmValue& value ) - { - read_string_or_throw( s, value ); - } - - bool json5_parser::read( std::wistream& is, wmValue& value ) - { - return read_stream( is, value ); - } - - void json5_parser::read_or_throw( std::wistream& is, wmValue& value ) - { - read_stream_or_throw( is, value ); - } - - bool json5_parser::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) - { - return read_range( begin, end, value ); - } - - void json5_parser::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) - { - begin = read_range_or_throw( begin, end, value ); - } -#endif +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_reader.h" +#include "json5_parser_reader_template.h" + +using namespace json5_parser; + +#ifdef JSON_SPIRIT_VALUE_ENABLED +bool json5_parser::read(const std::string& s, Value& value) { + return read_string(s, value); +} + +void json5_parser::read_or_throw(const std::string& s, Value& value) { + read_string_or_throw(s, value); +} + +bool json5_parser::read(std::istream& is, Value& value) { + return read_stream(is, value); +} + +void json5_parser::read_or_throw(std::istream& is, Value& value) { + read_stream_or_throw(is, value); +} + +bool json5_parser::read(std::string::const_iterator& begin, + std::string::const_iterator end, Value& value) { + return read_range(begin, end, value); +} + +void json5_parser::read_or_throw(std::string::const_iterator& begin, + std::string::const_iterator end, Value& value) { + begin = read_range_or_throw(begin, end, value); +} +#endif + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +bool json5_parser::read(const std::wstring& s, wValue& value) { + return read_string(s, value); +} + +void json5_parser::read_or_throw(const std::wstring& s, wValue& value) { + read_string_or_throw(s, value); +} + +bool json5_parser::read(std::wistream& is, wValue& value) { + return read_stream(is, value); +} + +void json5_parser::read_or_throw(std::wistream& is, wValue& value) { + read_stream_or_throw(is, value); +} + +bool json5_parser::read(std::wstring::const_iterator& begin, + std::wstring::const_iterator end, wValue& value) { + return read_range(begin, end, value); +} + +void json5_parser::read_or_throw(std::wstring::const_iterator& begin, + std::wstring::const_iterator end, wValue& value) { + begin = read_range_or_throw(begin, end, value); +} +#endif + +#ifdef JSON_SPIRIT_MVALUE_ENABLED +bool json5_parser::read(const std::string& s, mValue& value) { + return read_string(s, value); +} + +void json5_parser::read_or_throw(const std::string& s, mValue& value) { + read_string_or_throw(s, value); +} + +bool json5_parser::read(std::istream& is, mValue& value) { + return read_stream(is, value); +} + +void json5_parser::read_or_throw(std::istream& is, mValue& value) { + read_stream_or_throw(is, value); +} + +bool json5_parser::read(std::string::const_iterator& begin, + std::string::const_iterator end, mValue& value) { + return read_range(begin, end, value); +} + +void json5_parser::read_or_throw(std::string::const_iterator& begin, + std::string::const_iterator end, mValue& value) { + begin = read_range_or_throw(begin, end, value); +} +#endif + +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +bool json5_parser::read(const std::wstring& s, wmValue& value) { + return read_string(s, value); +} + +void json5_parser::read_or_throw(const std::wstring& s, wmValue& value) { + read_string_or_throw(s, value); +} + +bool json5_parser::read(std::wistream& is, wmValue& value) { + return read_stream(is, value); +} + +void json5_parser::read_or_throw(std::wistream& is, wmValue& value) { + read_stream_or_throw(is, value); +} + +bool json5_parser::read(std::wstring::const_iterator& begin, + std::wstring::const_iterator end, wmValue& value) { + return read_range(begin, end, value); +} + +void json5_parser::read_or_throw(std::wstring::const_iterator& begin, + std::wstring::const_iterator end, wmValue& value) { + begin = read_range_or_throw(begin, end, value); +} +#endif diff --git a/json5_parser/json5_parser_reader.h b/json5_parser/json5_parser_reader.h index 023c18c..b41ad9d 100644 --- a/json5_parser/json5_parser_reader.h +++ b/json5_parser/json5_parser_reader.h @@ -1,62 +1,69 @@ -#ifndef JSON_SPIRIT_READER -#define JSON_SPIRIT_READER - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json5_parser_value.h" -#include "json5_parser_error_position.h" -#include - -namespace json5_parser -{ - // functions to reads a JSON values - -#ifdef JSON_SPIRIT_VALUE_ENABLED - bool read( const std::string& s, Value& value ); - bool read( std::istream& is, Value& value ); - bool read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ); - - void read_or_throw( const std::string& s, Value& value ); - void read_or_throw( std::istream& is, Value& value ); - void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ); -#endif - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - bool read( const std::wstring& s, wValue& value ); - bool read( std::wistream& is, wValue& value ); - bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ); - - void read_or_throw( const std::wstring& s, wValue& value ); - void read_or_throw( std::wistream& is, wValue& value ); - void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ); -#endif - -#ifdef JSON_SPIRIT_MVALUE_ENABLED - bool read( const std::string& s, mValue& value ); - bool read( std::istream& is, mValue& value ); - bool read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ); - - void read_or_throw( const std::string& s, mValue& value ); - void read_or_throw( std::istream& is, mValue& value ); - void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ); -#endif - -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - bool read( const std::wstring& s, wmValue& value ); - bool read( std::wistream& is, wmValue& value ); - bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ); - - void read_or_throw( const std::wstring& s, wmValue& value ); - void read_or_throw( std::wistream& is, wmValue& value ); - void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ); -#endif -} - -#endif +#ifndef JSON_SPIRIT_READER +#define JSON_SPIRIT_READER + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include +#include "json5_parser_error_position.h" +#include "json5_parser_value.h" + +namespace json5_parser { +// functions to reads a JSON values + +#ifdef JSON_SPIRIT_VALUE_ENABLED +bool read(const std::string& s, Value& value); +bool read(std::istream& is, Value& value); +bool read(std::string::const_iterator& begin, std::string::const_iterator end, + Value& value); + +void read_or_throw(const std::string& s, Value& value); +void read_or_throw(std::istream& is, Value& value); +void read_or_throw(std::string::const_iterator& begin, std::string::const_iterator end, + Value& value); +#endif + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +bool read(const std::wstring& s, wValue& value); +bool read(std::wistream& is, wValue& value); +bool read(std::wstring::const_iterator& begin, std::wstring::const_iterator end, + wValue& value); + +void read_or_throw(const std::wstring& s, wValue& value); +void read_or_throw(std::wistream& is, wValue& value); +void read_or_throw(std::wstring::const_iterator& begin, + std::wstring::const_iterator end, wValue& value); +#endif + +#ifdef JSON_SPIRIT_MVALUE_ENABLED +bool read(const std::string& s, mValue& value); +bool read(std::istream& is, mValue& value); +bool read(std::string::const_iterator& begin, std::string::const_iterator end, + mValue& value); + +void read_or_throw(const std::string& s, mValue& value); +void read_or_throw(std::istream& is, mValue& value); +void read_or_throw(std::string::const_iterator& begin, std::string::const_iterator end, + mValue& value); +#endif + +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +bool read(const std::wstring& s, wmValue& value); +bool read(std::wistream& is, wmValue& value); +bool read(std::wstring::const_iterator& begin, std::wstring::const_iterator end, + wmValue& value); + +void read_or_throw(const std::wstring& s, wmValue& value); +void read_or_throw(std::wistream& is, wmValue& value); +void read_or_throw(std::wstring::const_iterator& begin, + std::wstring::const_iterator end, wmValue& value); +#endif +} // namespace json5_parser + +#endif diff --git a/json5_parser/json5_parser_reader_template.h b/json5_parser/json5_parser_reader_template.h index 557035b..be9950e 100644 --- a/json5_parser/json5_parser_reader_template.h +++ b/json5_parser/json5_parser_reader_template.h @@ -1,701 +1,623 @@ -#ifndef JSON_SPIRIT_READER_TEMPLATE -#define JSON_SPIRIT_READER_TEMPLATE - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json5_parser_value.h" -#include "json5_parser_error_position.h" - -#define BOOST_SPIRIT_THREADSAFE // uncomment for multithreaded use, requires linking to boost.thread - -#include -#include -#include - -#if BOOST_VERSION >= 103800 - #include - #include - #include - #include - #include - #define spirit_namespace boost::spirit::classic -#else - #include - #include - #include - #include - #include - #define spirit_namespace boost::spirit -#endif - -namespace json5_parser -{ - const spirit_namespace::int_parser < boost::int64_t > int64_p = spirit_namespace::int_parser < boost::int64_t >(); - const spirit_namespace::uint_parser< boost::uint64_t > uint64_p = spirit_namespace::uint_parser< boost::uint64_t >(); - - template< class Iter_type > - bool is_eq( Iter_type first, Iter_type last, const char* c_str ) - { - for( Iter_type i = first; i != last; ++i, ++c_str ) - { - if( *c_str == 0 ) return false; - - if( *i != *c_str ) return false; - } - - return true; - } - - template< class Char_type > - Char_type hex_to_num( const Char_type c ) - { - if( ( c >= '0' ) && ( c <= '9' ) ) return c - '0'; - if( ( c >= 'a' ) && ( c <= 'f' ) ) return c - 'a' + 10; - if( ( c >= 'A' ) && ( c <= 'F' ) ) return c - 'A' + 10; - return 0; - } - - template< class Char_type, class Iter_type > - Char_type hex_str_to_char( Iter_type& begin ) - { - const Char_type c1( *( ++begin ) ); - const Char_type c2( *( ++begin ) ); - - return ( hex_to_num( c1 ) << 4 ) + hex_to_num( c2 ); - } - - template< class Char_type, class Iter_type > - Char_type unicode_str_to_char( Iter_type& begin ) - { - const Char_type c1( *( ++begin ) ); - const Char_type c2( *( ++begin ) ); - const Char_type c3( *( ++begin ) ); - const Char_type c4( *( ++begin ) ); - - return ( hex_to_num( c1 ) << 12 ) + - ( hex_to_num( c2 ) << 8 ) + - ( hex_to_num( c3 ) << 4 ) + - hex_to_num( c4 ); - } - - template< class String_type > - void append_esc_char_and_incr_iter( String_type& s, - typename String_type::const_iterator& begin, - typename String_type::const_iterator end ) - { - typedef typename String_type::value_type Char_type; - - const Char_type c2( *begin ); - - switch( c2 ) - { - case 't': s += '\t'; break; - case 'b': s += '\b'; break; - case 'f': s += '\f'; break; - case 'n': s += '\n'; break; - case 'r': s += '\r'; break; - case '\\': s += '\\'; break; - case '/': s += '/'; break; - case '"': s += '"'; break; - case 'x': - { - if( end - begin >= 3 ) // expecting "xHH..." - { - s += hex_str_to_char< Char_type >( begin ); - } - break; - } - case 'u': - { - if( end - begin >= 5 ) // expecting "uHHHH..." - { - s += unicode_str_to_char< Char_type >( begin ); - } - break; - } - case '\n': break; // skip escaped newlines - } - } - - template< class String_type > - String_type substitute_esc_chars( typename String_type::const_iterator begin, - typename String_type::const_iterator end ) - { - typedef typename String_type::const_iterator Iter_type; - - if( end - begin < 2 ) return String_type( begin, end ); - - String_type result; - - result.reserve( end - begin ); - - const Iter_type end_minus_1( end - 1 ); - - Iter_type substr_start = begin; - Iter_type i = begin; - - for( ; i < end_minus_1; ++i ) - { - if( *i == '\\' ) - { - result.append( substr_start, i ); - - ++i; // skip the '\' - - append_esc_char_and_incr_iter( result, i, end ); - - substr_start = i + 1; - } - } - - result.append( substr_start, end ); - - return result; - } - - template< class String_type > - String_type get_str_( typename String_type::const_iterator begin, - typename String_type::const_iterator end ) - { - assert( end - begin >= 2 ); - - typedef typename String_type::const_iterator Iter_type; - - Iter_type str_without_quotes( ++begin ); - Iter_type end_without_quotes( --end ); - - return substitute_esc_chars< String_type >( str_without_quotes, end_without_quotes ); - } - - inline std::string get_str( std::string::const_iterator begin, std::string::const_iterator end ) - { - return get_str_< std::string >( begin, end ); - } - - inline std::wstring get_str( std::wstring::const_iterator begin, std::wstring::const_iterator end ) - { - return get_str_< std::wstring >( begin, end ); - } - - template< class String_type, class Iter_type > - String_type get_str( Iter_type begin, Iter_type end ) - { - const String_type tmp( begin, end ); // convert multipass iterators to string iterators - - return get_str( tmp.begin(), tmp.end() ); - } - - // this class's methods get called by the spirit parse resulting - // in the creation of a JSON object or array - // - // NB Iter_type could be a std::string iterator, wstring iterator, a position iterator or a multipass iterator - // - template< class Value_type, class Iter_type > - class Semantic_actions - { - public: - - typedef typename Value_type::Config_type Config_type; - typedef typename Config_type::String_type String_type; - typedef typename Config_type::Object_type Object_type; - typedef typename Config_type::Array_type Array_type; - typedef typename String_type::value_type Char_type; - - Semantic_actions( Value_type& value ) - : value_( value ) - , current_p_( 0 ) - { - } - - void begin_obj( Char_type c ) - { - assert( c == '{' ); - - begin_compound< Object_type >(); - } - - void end_obj( Char_type c ) - { - assert( c == '}' ); - - end_compound(); - } - - void begin_array( Char_type c ) - { - assert( c == '[' ); - - begin_compound< Array_type >(); - } - - void end_array( Char_type c ) - { - assert( c == ']' ); - - end_compound(); - } - - void new_name( Iter_type begin, Iter_type end ) - { - assert( current_p_->type() == obj_type ); - - name_ = get_str< String_type >( begin, end ); - } - - void new_identifier( Iter_type begin, Iter_type end ) - { - assert( current_p_->type() == obj_type ); - - String_type result; - result.append(begin,end); - name_ = result; - } - - void new_str( Iter_type begin, Iter_type end ) - { - add_to_current( get_str< String_type >( begin, end ) ); - } - - void new_true( Iter_type begin, Iter_type end ) - { - assert( is_eq( begin, end, "true" ) ); - - add_to_current( true ); - } - - void new_false( Iter_type begin, Iter_type end ) - { - assert( is_eq( begin, end, "false" ) ); - - add_to_current( false ); - } - - void new_null( Iter_type begin, Iter_type end ) - { - assert( is_eq( begin, end, "null" ) ); - - add_to_current( Value_type() ); - } - - void new_int( boost::int64_t i ) - { - add_to_current( i ); - } - - void new_uint64( boost::uint64_t ui ) - { - add_to_current( ui ); - } - - void new_real( double d ) - { - add_to_current( d ); - } - - void new_infinity( Iter_type begin, Iter_type end ) - { - assert( is_eq( begin, end, "Infinity" ) ); - - add_to_current( std::numeric_limits::infinity() ); - } - - void new_minus_infinity( Iter_type begin, Iter_type end ) - { - assert( is_eq( begin, end, "-Infinity" ) ); - - add_to_current( -std::numeric_limits::infinity() ); - } - - private: - - Semantic_actions& operator=( const Semantic_actions& ); - // to prevent "assignment operator could not be generated" warning - - Value_type* add_first( const Value_type& value ) - { - assert( current_p_ == 0 ); - - value_ = value; - current_p_ = &value_; - return current_p_; - } - - template< class Array_or_obj > - void begin_compound() - { - if( current_p_ == 0 ) - { - add_first( Array_or_obj() ); - } - else - { - stack_.push_back( current_p_ ); - - Array_or_obj new_array_or_obj; // avoid copy by building new array or object in place - - current_p_ = add_to_current( new_array_or_obj ); - } - } - - void end_compound() - { - if( current_p_ != &value_ ) - { - current_p_ = stack_.back(); - - stack_.pop_back(); - } - } - - Value_type* add_to_current( const Value_type& value ) - { - if( current_p_ == 0 ) - { - return add_first( value ); - } - else if( current_p_->type() == array_type ) - { - current_p_->get_array().push_back( value ); - - return ¤t_p_->get_array().back(); - } - - assert( current_p_->type() == obj_type ); - - return &Config_type::add( current_p_->get_obj(), name_, value ); - } - - Value_type& value_; // this is the object or array that is being created - Value_type* current_p_; // the child object or array that is currently being constructed - - std::vector< Value_type* > stack_; // previous child objects and arrays - - String_type name_; // of current name/value pair - }; - - template< typename Iter_type > - void throw_error( spirit_namespace::position_iterator< Iter_type > i, const std::string& reason ) - { - throw Error_position( i.get_position().line, i.get_position().column, reason ); - } - - template< typename Iter_type > - void throw_error( Iter_type , const std::string& reason ) - { - throw reason; - } - - // the spirit grammer - // - template< class Value_type, class Iter_type > - class Json_grammer : public spirit_namespace::grammar< Json_grammer< Value_type, Iter_type > > - { - public: - - typedef Semantic_actions< Value_type, Iter_type > Semantic_actions_t; - - Json_grammer( Semantic_actions_t& semantic_actions ) - : actions_( semantic_actions ) - { - } - - static void throw_not_value( Iter_type begin, Iter_type ) - { - throw_error( begin, "not a value" ); - } - - static void throw_not_hex( Iter_type begin, Iter_type ) - { - throw_error( begin, "not a hexadecimal number" ); - } - - static void throw_not_array( Iter_type begin, Iter_type ) - { - throw_error( begin, "not an array" ); - } - - static void throw_not_object( Iter_type begin, Iter_type ) - { - throw_error( begin, "not an object" ); - } - - static void throw_not_pair( Iter_type begin, Iter_type ) - { - throw_error( begin, "not a pair" ); - } - - static void throw_not_colon( Iter_type begin, Iter_type ) - { - throw_error( begin, "no colon in pair" ); - } - - static void throw_not_string( Iter_type begin, Iter_type ) - { - throw_error( begin, "not a string" ); - } - - template< typename ScannerT > - class definition - { - public: - - definition( const Json_grammer& self ) - { - using namespace spirit_namespace; - - typedef typename Value_type::String_type::value_type Char_type; - - // first we convert the semantic action class methods to functors with the - // parameter signature expected by spirit - - typedef boost::function< void( Char_type ) > Char_action; - typedef boost::function< void( Iter_type, Iter_type ) > Str_action; - typedef boost::function< void( double ) > Real_action; - typedef boost::function< void( boost::int64_t ) > Int_action; - typedef boost::function< void( boost::uint64_t ) > Uint64_action; - - Char_action begin_obj ( boost::bind( &Semantic_actions_t::begin_obj, &self.actions_, _1 ) ); - Char_action end_obj ( boost::bind( &Semantic_actions_t::end_obj, &self.actions_, _1 ) ); - Char_action begin_array( boost::bind( &Semantic_actions_t::begin_array, &self.actions_, _1 ) ); - Char_action end_array ( boost::bind( &Semantic_actions_t::end_array, &self.actions_, _1 ) ); - Str_action new_name ( boost::bind( &Semantic_actions_t::new_name, &self.actions_, _1, _2 ) ); - Str_action new_identifier( boost::bind( &Semantic_actions_t::new_identifier, &self.actions_, _1, _2 ) ); - Str_action new_str ( boost::bind( &Semantic_actions_t::new_str, &self.actions_, _1, _2 ) ); - Str_action new_true ( boost::bind( &Semantic_actions_t::new_true, &self.actions_, _1, _2 ) ); - Str_action new_false ( boost::bind( &Semantic_actions_t::new_false, &self.actions_, _1, _2 ) ); - Str_action new_null ( boost::bind( &Semantic_actions_t::new_null, &self.actions_, _1, _2 ) ); - Real_action new_real ( boost::bind( &Semantic_actions_t::new_real, &self.actions_, _1 ) ); - Str_action new_infinity ( boost::bind( &Semantic_actions_t::new_infinity, &self.actions_, _1, _2 ) ); - Str_action new_minus_infinity ( boost::bind( &Semantic_actions_t::new_minus_infinity, &self.actions_, _1, _2 ) ); - Int_action new_int ( boost::bind( &Semantic_actions_t::new_int, &self.actions_, _1 ) ); - Uint64_action new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64, &self.actions_, _1 ) ); - - // actual grammer - - json_ - = value_ | eps_p[ &throw_not_value ] - ; - - value_ - = single_quoted_string_[ new_str ] - | double_quoted_string_[ new_str ] - | number_ - | object_ - | array_ - | str_p( "true" ) [ new_true ] - | str_p( "false" )[ new_false ] - | str_p( "null" ) [ new_null ] - | (!ch_p('+') >> str_p( "Infinity" ) [ new_infinity ]) - | str_p( "-Infinity" ) [ new_minus_infinity ] - ; - - object_ - = ch_p('{')[ begin_obj ] - >> !members_ - >> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] ) - ; - - members_ - = pair_ >> *( ',' >> pair_ ) >> !ch_p(',') - ; - - pair_ - = (double_quoted_string_[ new_name ] | identifier_[ new_identifier ]) - >> ( ':' | eps_p[ &throw_not_colon ] ) - >> ( value_ | eps_p[ &throw_not_value ] ) - ; - - array_ - = ch_p('[')[ begin_array ] - >> !elements_ - >> ( ch_p(']')[ end_array ] | eps_p[ &throw_not_array ] ) - ; - - elements_ - = value_ >> *( ',' >> value_ ) >> !ch_p(',') - ; - - double_quoted_string_ - = lexeme_d // this causes white space and what would appear to be comments inside a string to be retained - [ - confix_p - ( - '"', - *lex_escape_ch_p, - '"' - ) - ] - ; - - single_quoted_string_ - = lexeme_d // this causes white space and what would appear to be comments inside a string to be retained - [ - confix_p - ( - '\'', - *lex_escape_ch_p, - '\'' - ) - ] - ; - - identifier_ - = (alpha_p | ch_p('_') | ch_p('$')) >> *(alnum_p | ch_p('_') | ch_p('$')); - - number_ - = ( str_p("0x") >> (hex_p[ new_int ] | eps_p[ &throw_not_hex ] ) ) - | strict_real_p[ new_real ] - | int64_p [ new_int ] - | uint64_p [ new_uint64 ] - ; - } - - spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, single_quoted_string_, double_quoted_string_, number_, identifier_; - - const spirit_namespace::rule< ScannerT >& start() const { return json_; } - }; - - private: - - Json_grammer& operator=( const Json_grammer& ); // to prevent "assignment operator could not be generated" warning - - Semantic_actions_t& actions_; - }; - - template< class Iter_type, class Value_type > - void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) - { - typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t; - - const Posn_iter_t posn_begin( begin, end ); - const Posn_iter_t posn_end( end, end ); - - read_range_or_throw( posn_begin, posn_end, value ); - } - - template< class Istream_type > - struct Multi_pass_iters - { - typedef typename Istream_type::char_type Char_type; - typedef std::istream_iterator< Char_type, Char_type > istream_iter; - typedef spirit_namespace::multi_pass< istream_iter > Mp_iter; - - Multi_pass_iters( Istream_type& is ) - { - is.unsetf( std::ios::skipws ); - - begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) ); - end_ = spirit_namespace::make_multi_pass( istream_iter() ); - } - - Mp_iter begin_; - Mp_iter end_; - }; - - // reads a JSON Value from a pair of input iterators throwing an exception on invalid input, e.g. - // - // string::const_iterator start = str.begin(); - // const string::const_iterator next = read_range_or_throw( str.begin(), str.end(), value ); - // - // The iterator 'next' will point to the character past the - // last one read. - // - template< class Iter_type, class Value_type > - Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) - { - Semantic_actions< Value_type, Iter_type > semantic_actions( value ); - - const spirit_namespace::parse_info< Iter_type > info = - spirit_namespace::parse( begin, end, - Json_grammer< Value_type, Iter_type >( semantic_actions ), - spirit_namespace::space_p | - spirit_namespace::comment_p("//") | - spirit_namespace::comment_p("/*", "*/") ); - - if( !info.hit ) - { - assert( false ); // in theory exception should already have been thrown - throw_error( info.stop, "error" ); - } - - return info.stop; - } - - // reads a JSON Value from a pair of input iterators, e.g. - // - // string::const_iterator start = str.begin(); - // const bool success = read_string( start, str.end(), value ); - // - // The iterator 'start' will point to the character past the - // last one read. - // - template< class Iter_type, class Value_type > - bool read_range( Iter_type& begin, Iter_type end, Value_type& value ) - { - try - { - begin = read_range_or_throw( begin, end, value ); - - return true; - } - catch( ... ) - { - return false; - } - } - - // reads a JSON Value from a string, e.g. - // - // const bool success = read_string( str, value ); - // - template< class String_type, class Value_type > - bool read_string( const String_type& s, Value_type& value ) - { - typename String_type::const_iterator begin = s.begin(); - - return read_range( begin, s.end(), value ); - } - - // reads a JSON Value from a string throwing an exception on invalid input, e.g. - // - // read_string_or_throw( is, value ); - // - template< class String_type, class Value_type > - void read_string_or_throw( const String_type& s, Value_type& value ) - { - add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value ); - } - - // reads a JSON Value from a stream, e.g. - // - // const bool success = read_stream( is, value ); - // - template< class Istream_type, class Value_type > - bool read_stream( Istream_type& is, Value_type& value ) - { - Multi_pass_iters< Istream_type > mp_iters( is ); - - return read_range( mp_iters.begin_, mp_iters.end_, value ); - } - - // reads a JSON Value from a stream throwing an exception on invalid input, e.g. - // - // read_stream_or_throw( is, value ); - // - template< class Istream_type, class Value_type > - void read_stream_or_throw( Istream_type& is, Value_type& value ) - { - const Multi_pass_iters< Istream_type > mp_iters( is ); - - add_posn_iter_and_read_range_or_throw( mp_iters.begin_, mp_iters.end_, value ); - } -} - -#endif +#ifndef JSON_SPIRIT_READER_TEMPLATE +#define JSON_SPIRIT_READER_TEMPLATE + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include +#include + +#include "json5_parser_error_position.h" +#include "json5_parser_value.h" + +#define BOOST_SPIRIT_THREADSAFE // uncomment for multithreaded use, requires linking to + // boost.thread + +#include +#include +#include + +#if BOOST_VERSION >= 103800 +#include +#include +#include +#include +#include +#define spirit_namespace boost::spirit::classic +#else +#include +#include +#include +#include +#include +#define spirit_namespace boost::spirit +#endif + +namespace json5_parser { +const spirit_namespace::int_parser int64_p = + spirit_namespace::int_parser(); +const spirit_namespace::uint_parser uint64_p = + spirit_namespace::uint_parser(); + +template +bool is_eq(Iter_type first, Iter_type last, const char* c_str) { + for (Iter_type i = first; i != last; ++i, ++c_str) { + if (*c_str == 0) return false; + + if (*i != *c_str) return false; + } + + return true; +} + +template +Char_type hex_to_num(const Char_type c) { + if ((c >= '0') && (c <= '9')) return c - '0'; + if ((c >= 'a') && (c <= 'f')) return c - 'a' + 10; + if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10; + return 0; +} + +template +Char_type hex_str_to_char(Iter_type& begin) { + const Char_type c1(*(++begin)); + const Char_type c2(*(++begin)); + + return (hex_to_num(c1) << 4) + hex_to_num(c2); +} + +template +Char_type unicode_str_to_char(Iter_type& begin) { + const Char_type c1(*(++begin)); + const Char_type c2(*(++begin)); + const Char_type c3(*(++begin)); + const Char_type c4(*(++begin)); + + return (hex_to_num(c1) << 12) + (hex_to_num(c2) << 8) + (hex_to_num(c3) << 4) + + hex_to_num(c4); +} + +template +void append_esc_char_and_incr_iter(String_type& s, + typename String_type::const_iterator& begin, + typename String_type::const_iterator end) { + typedef typename String_type::value_type Char_type; + + const Char_type c2(*begin); + + switch (c2) { + case 't': + s += '\t'; + break; + case 'b': + s += '\b'; + break; + case 'f': + s += '\f'; + break; + case 'n': + s += '\n'; + break; + case 'r': + s += '\r'; + break; + case '\\': + s += '\\'; + break; + case '/': + s += '/'; + break; + case '"': + s += '"'; + break; + case 'x': { + if (end - begin >= 3) // expecting "xHH..." + { + s += hex_str_to_char(begin); + } + break; + } + case 'u': { + if (end - begin >= 5) // expecting "uHHHH..." + { + s += unicode_str_to_char(begin); + } + break; + } + case '\n': + break; // skip escaped newlines + } +} + +template +String_type substitute_esc_chars(typename String_type::const_iterator begin, + typename String_type::const_iterator end) { + typedef typename String_type::const_iterator Iter_type; + + if (end - begin < 2) return String_type(begin, end); + + String_type result; + + result.reserve(end - begin); + + const Iter_type end_minus_1(end - 1); + + Iter_type substr_start = begin; + Iter_type i = begin; + + for (; i < end_minus_1; ++i) { + if (*i == '\\') { + result.append(substr_start, i); + + ++i; // skip the '\' + + append_esc_char_and_incr_iter(result, i, end); + + substr_start = i + 1; + } + } + + result.append(substr_start, end); + + return result; +} + +template +String_type get_str_(typename String_type::const_iterator begin, + typename String_type::const_iterator end) { + assert(end - begin >= 2); + + typedef typename String_type::const_iterator Iter_type; + + Iter_type str_without_quotes(++begin); + Iter_type end_without_quotes(--end); + + return substitute_esc_chars(str_without_quotes, end_without_quotes); +} + +inline std::string get_str(std::string::const_iterator begin, + std::string::const_iterator end) { + return get_str_(begin, end); +} + +inline std::wstring get_str(std::wstring::const_iterator begin, + std::wstring::const_iterator end) { + return get_str_(begin, end); +} + +template +String_type get_str(Iter_type begin, Iter_type end) { + const String_type tmp(begin, + end); // convert multipass iterators to string iterators + + return get_str(tmp.begin(), tmp.end()); +} + +// this class's methods get called by the spirit parse resulting +// in the creation of a JSON object or array +// +// NB Iter_type could be a std::string iterator, wstring iterator, a position iterator +// or a multipass iterator +// +template +class Semantic_actions { +public: + typedef typename Value_type::Config_type Config_type; + typedef typename Config_type::String_type String_type; + typedef typename Config_type::Object_type Object_type; + typedef typename Config_type::Array_type Array_type; + typedef typename String_type::value_type Char_type; + + Semantic_actions(Value_type& value) : value_(value), current_p_(0) {} + + void begin_obj(Char_type c) { + assert(c == '{'); + + begin_compound(); + } + + void end_obj(Char_type c) { + assert(c == '}'); + + end_compound(); + } + + void begin_array(Char_type c) { + assert(c == '['); + + begin_compound(); + } + + void end_array(Char_type c) { + assert(c == ']'); + + end_compound(); + } + + void new_name(Iter_type begin, Iter_type end) { + assert(current_p_->type() == obj_type); + + name_ = get_str(begin, end); + } + + void new_identifier(Iter_type begin, Iter_type end) { + assert(current_p_->type() == obj_type); + + String_type result; + result.append(begin, end); + name_ = boost::algorithm::trim_right_copy(result); + } + + void new_str(Iter_type begin, Iter_type end) { + add_to_current(get_str(begin, end)); + } + + void new_true(Iter_type begin, Iter_type end) { + assert(is_eq(begin, end, "true")); + + add_to_current(true); + } + + void new_false(Iter_type begin, Iter_type end) { + assert(is_eq(begin, end, "false")); + + add_to_current(false); + } + + void new_null(Iter_type begin, Iter_type end) { + assert(is_eq(begin, end, "null")); + + add_to_current(Value_type()); + } + + void new_int(boost::int64_t i) { add_to_current(i); } + + void new_uint64(boost::uint64_t ui) { add_to_current(ui); } + + void new_real(double d) { add_to_current(d); } + + void new_infinity(Iter_type begin, Iter_type end) { + assert(is_eq(begin, end, "Infinity")); + + add_to_current(std::numeric_limits::infinity()); + } + + void new_minus_infinity(Iter_type begin, Iter_type end) { + assert(is_eq(begin, end, "-Infinity")); + + add_to_current(-std::numeric_limits::infinity()); + } + +private: + Semantic_actions& operator=(const Semantic_actions&); + // to prevent "assignment operator could not be generated" warning + + Value_type* add_first(const Value_type& value) { + assert(current_p_ == 0); + + value_ = value; + current_p_ = &value_; + return current_p_; + } + + template + void begin_compound() { + if (current_p_ == 0) { + add_first(Array_or_obj()); + } else { + stack_.push_back(current_p_); + + Array_or_obj new_array_or_obj; // avoid copy by building new array or + // object in place + + current_p_ = add_to_current(new_array_or_obj); + } + } + + void end_compound() { + if (current_p_ != &value_) { + current_p_ = stack_.back(); + + stack_.pop_back(); + } + } + + Value_type* add_to_current(const Value_type& value) { + if (current_p_ == 0) { + return add_first(value); + } else if (current_p_->type() == array_type) { + current_p_->get_array().push_back(value); + + return ¤t_p_->get_array().back(); + } + + assert(current_p_->type() == obj_type); + + return &Config_type::add(current_p_->get_obj(), name_, value); + } + + Value_type& value_; // this is the object or array that is being created + Value_type* current_p_; // the child object or array that is currently being + // constructed + + std::vector stack_; // previous child objects and arrays + + String_type name_; // of current name/value pair +}; + +template +void throw_error(spirit_namespace::position_iterator i, + const std::string& reason) { + throw Error_position(i.get_position().line, i.get_position().column, reason); +} + +template +void throw_error(Iter_type, const std::string& reason) { + throw reason; +} + +// the spirit grammar +// +template +class Json_grammar + : public spirit_namespace::grammar > { +public: + typedef Semantic_actions Semantic_actions_t; + + Json_grammar(Semantic_actions_t& semantic_actions) : actions_(semantic_actions) {} + + static void throw_not_value(Iter_type begin, Iter_type) { + throw_error(begin, "not a value"); + } + + static void throw_not_hex(Iter_type begin, Iter_type) { + throw_error(begin, "not a hexadecimal number"); + } + + static void throw_not_array(Iter_type begin, Iter_type) { + throw_error(begin, "not an array"); + } + + static void throw_not_object(Iter_type begin, Iter_type) { + throw_error(begin, "not an object"); + } + + static void throw_not_pair(Iter_type begin, Iter_type) { + throw_error(begin, "not a pair"); + } + + static void throw_not_colon(Iter_type begin, Iter_type) { + throw_error(begin, "no colon in pair"); + } + + static void throw_not_string(Iter_type begin, Iter_type) { + throw_error(begin, "not a string"); + } + + template + class definition { + public: + definition(const Json_grammar& self) { + using namespace spirit_namespace; + + typedef typename Value_type::String_type::value_type Char_type; + + // first we convert the semantic action class methods to functors with the + // parameter signature expected by spirit + + typedef boost::function Char_action; + typedef boost::function Str_action; + typedef boost::function Real_action; + typedef boost::function Int_action; + typedef boost::function Uint64_action; + + Char_action begin_obj( + boost::bind(&Semantic_actions_t::begin_obj, &self.actions_, _1)); + Char_action end_obj( + boost::bind(&Semantic_actions_t::end_obj, &self.actions_, _1)); + Char_action begin_array( + boost::bind(&Semantic_actions_t::begin_array, &self.actions_, _1)); + Char_action end_array( + boost::bind(&Semantic_actions_t::end_array, &self.actions_, _1)); + Str_action new_name( + boost::bind(&Semantic_actions_t::new_name, &self.actions_, _1, _2)); + Str_action new_identifier(boost::bind(&Semantic_actions_t::new_identifier, + &self.actions_, _1, _2)); + Str_action new_str( + boost::bind(&Semantic_actions_t::new_str, &self.actions_, _1, _2)); + Str_action new_true( + boost::bind(&Semantic_actions_t::new_true, &self.actions_, _1, _2)); + Str_action new_false(boost::bind(&Semantic_actions_t::new_false, + &self.actions_, _1, _2)); + Str_action new_null( + boost::bind(&Semantic_actions_t::new_null, &self.actions_, _1, _2)); + Real_action new_real( + boost::bind(&Semantic_actions_t::new_real, &self.actions_, _1)); + Str_action new_infinity(boost::bind(&Semantic_actions_t::new_infinity, + &self.actions_, _1, _2)); + Str_action new_minus_infinity(boost::bind( + &Semantic_actions_t::new_minus_infinity, &self.actions_, _1, _2)); + Int_action new_int( + boost::bind(&Semantic_actions_t::new_int, &self.actions_, _1)); + Uint64_action new_uint64( + boost::bind(&Semantic_actions_t::new_uint64, &self.actions_, _1)); + + // actual grammar + + json_ = value_ | eps_p[&throw_not_value]; + + value_ = single_quoted_string_[new_str] | double_quoted_string_[new_str] | + number_ | object_ | array_ | str_p("true")[new_true] | + str_p("false")[new_false] | str_p("null")[new_null] | + (!ch_p('+') >> str_p("Infinity")[new_infinity]) | + str_p("-Infinity")[new_minus_infinity]; + + object_ = ch_p('{')[begin_obj] >> !members_ >> + (ch_p('}')[end_obj] | eps_p[&throw_not_object]); + + members_ = pair_ >> *(',' >> pair_) >> !ch_p(','); + + pair_ = (double_quoted_string_[new_name] | identifier_[new_identifier]) >> + (':' | eps_p[&throw_not_colon]) >> + (value_ | eps_p[&throw_not_value]); + + array_ = ch_p('[')[begin_array] >> !elements_ >> + (ch_p(']')[end_array] | eps_p[&throw_not_array]); + + elements_ = value_ >> *(',' >> value_) >> !ch_p(','); + + double_quoted_string_ = + lexeme_d // this causes white space and what would appear to be + // comments inside a string to be retained + [confix_p('"', *lex_escape_ch_p, '"')]; + + single_quoted_string_ = + lexeme_d // this causes white space and what would appear to be + // comments inside a string to be retained + [confix_p('\'', *lex_escape_ch_p, '\'')]; + + identifier_ = (alpha_p | ch_p('_') | ch_p('$')) >> + *(alnum_p | ch_p('_') | ch_p('$')); + + number_ = (str_p("0x") >> (hex_p[new_int] | eps_p[&throw_not_hex])) | + strict_real_p[new_real] | int64_p[new_int] | uint64_p[new_uint64]; + } + + spirit_namespace::rule json_, object_, members_, pair_, array_, + elements_, value_, single_quoted_string_, double_quoted_string_, + number_, identifier_; + + const spirit_namespace::rule& start() const { return json_; } + }; + +private: + Json_grammar& operator=(const Json_grammar&); // to prevent "assignment operator + // could not be generated" warning + + Semantic_actions_t& actions_; +}; + +template +void add_posn_iter_and_read_range_or_throw(Iter_type begin, Iter_type end, + Value_type& value) { + typedef spirit_namespace::position_iterator Posn_iter_t; + + const Posn_iter_t posn_begin(begin, end); + const Posn_iter_t posn_end(end, end); + + read_range_or_throw(posn_begin, posn_end, value); +} + +template +struct Multi_pass_iters { + typedef typename Istream_type::char_type Char_type; + typedef std::istream_iterator istream_iter; + typedef spirit_namespace::multi_pass Mp_iter; + + Multi_pass_iters(Istream_type& is) { + is.unsetf(std::ios::skipws); + + begin_ = spirit_namespace::make_multi_pass(istream_iter(is)); + end_ = spirit_namespace::make_multi_pass(istream_iter()); + } + + Mp_iter begin_; + Mp_iter end_; +}; + +// reads a JSON Value from a pair of input iterators throwing an exception on invalid +// input, e.g. +// +// string::const_iterator start = str.begin(); +// const string::const_iterator next = read_range_or_throw( str.begin(), str.end(), +// value ); +// +// The iterator 'next' will point to the character past the +// last one read. +// +template +Iter_type read_range_or_throw(Iter_type begin, Iter_type end, Value_type& value) { + Semantic_actions semantic_actions(value); + + const spirit_namespace::parse_info info = spirit_namespace::parse( + begin, end, Json_grammar(semantic_actions), + spirit_namespace::space_p | spirit_namespace::comment_p("//") | + spirit_namespace::comment_p("/*", "*/")); + + if (!info.hit) { + assert(false); // in theory exception should already have been thrown + throw_error(info.stop, "error"); + } + + return info.stop; +} + +// reads a JSON Value from a pair of input iterators, e.g. +// +// string::const_iterator start = str.begin(); +// const bool success = read_string( start, str.end(), value ); +// +// The iterator 'start' will point to the character past the +// last one read. +// +template +bool read_range(Iter_type& begin, Iter_type end, Value_type& value) { + try { + begin = read_range_or_throw(begin, end, value); + + return true; + } catch (...) { + return false; + } +} + +// reads a JSON Value from a string, e.g. +// +// const bool success = read_string( str, value ); +// +template +bool read_string(const String_type& s, Value_type& value) { + typename String_type::const_iterator begin = s.begin(); + + return read_range(begin, s.end(), value); +} + +// reads a JSON Value from a string throwing an exception on invalid input, e.g. +// +// read_string_or_throw( is, value ); +// +template +void read_string_or_throw(const String_type& s, Value_type& value) { + add_posn_iter_and_read_range_or_throw(s.begin(), s.end(), value); +} + +// reads a JSON Value from a stream, e.g. +// +// const bool success = read_stream( is, value ); +// +template +bool read_stream(Istream_type& is, Value_type& value) { + Multi_pass_iters mp_iters(is); + + return read_range(mp_iters.begin_, mp_iters.end_, value); +} + +// reads a JSON Value from a stream throwing an exception on invalid input, e.g. +// +// read_stream_or_throw( is, value ); +// +template +void read_stream_or_throw(Istream_type& is, Value_type& value) { + const Multi_pass_iters mp_iters(is); + + add_posn_iter_and_read_range_or_throw(mp_iters.begin_, mp_iters.end_, value); +} +} // namespace json5_parser + +#endif diff --git a/json5_parser/json5_parser_stream_reader.h b/json5_parser/json5_parser_stream_reader.h index 39e71ec..d14022e 100644 --- a/json5_parser/json5_parser_stream_reader.h +++ b/json5_parser/json5_parser_stream_reader.h @@ -1,70 +1,56 @@ -#ifndef JSON_SPIRIT_READ_STREAM -#define JSON_SPIRIT_READ_STREAM - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json5_parser_reader_template.h" - -namespace json5_parser -{ - // these classes allows you to read multiple top level contiguous values from a stream, - // the normal stream read functions have a bug that prevent multiple top level values - // from being read unless they are separated by spaces - - template< class Istream_type, class Value_type > - class Stream_reader - { - public: - - Stream_reader( Istream_type& is ) - : iters_( is ) - { - } - - bool read_next( Value_type& value ) - { - return read_range( iters_.begin_, iters_.end_, value ); - } - - private: - - typedef Multi_pass_iters< Istream_type > Mp_iters; - - Mp_iters iters_; - }; - - template< class Istream_type, class Value_type > - class Stream_reader_thrower - { - public: - - Stream_reader_thrower( Istream_type& is ) - : iters_( is ) - , posn_begin_( iters_.begin_, iters_.end_ ) - , posn_end_( iters_.end_, iters_.end_ ) - { - } - - void read_next( Value_type& value ) - { - posn_begin_ = read_range_or_throw( posn_begin_, posn_end_, value ); - } - - private: - - typedef Multi_pass_iters< Istream_type > Mp_iters; - typedef spirit_namespace::position_iterator< typename Mp_iters::Mp_iter > Posn_iter_t; - - Mp_iters iters_; - Posn_iter_t posn_begin_, posn_end_; - }; -} - -#endif +#ifndef JSON_SPIRIT_READ_STREAM +#define JSON_SPIRIT_READ_STREAM + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "json5_parser_reader_template.h" + +namespace json5_parser { +// these classes allows you to read multiple top level contiguous values from a stream, +// the normal stream read functions have a bug that prevent multiple top level values +// from being read unless they are separated by spaces + +template +class Stream_reader { +public: + Stream_reader(Istream_type& is) : iters_(is) {} + + bool read_next(Value_type& value) { + return read_range(iters_.begin_, iters_.end_, value); + } + +private: + typedef Multi_pass_iters Mp_iters; + + Mp_iters iters_; +}; + +template +class Stream_reader_thrower { +public: + Stream_reader_thrower(Istream_type& is) + : iters_(is), + posn_begin_(iters_.begin_, iters_.end_), + posn_end_(iters_.end_, iters_.end_) {} + + void read_next(Value_type& value) { + posn_begin_ = read_range_or_throw(posn_begin_, posn_end_, value); + } + +private: + typedef Multi_pass_iters Mp_iters; + typedef spirit_namespace::position_iterator Posn_iter_t; + + Mp_iters iters_; + Posn_iter_t posn_begin_, posn_end_; +}; +} // namespace json5_parser + +#endif diff --git a/json5_parser/json5_parser_utils.h b/json5_parser/json5_parser_utils.h index f9b814a..331dd22 100644 --- a/json5_parser/json5_parser_utils.h +++ b/json5_parser/json5_parser_utils.h @@ -1,63 +1,56 @@ -#ifndef JSON_SPIRIT_UTILS -#define JSON_SPIRIT_UTILS - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json5_parser_value.h" -#include - -namespace json5_parser -{ - template< class Obj_t, class Map_t > - void obj_to_map( const Obj_t& obj, Map_t& mp_obj ) - { - mp_obj.clear(); - - for( typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i ) - { - mp_obj[ i->name_ ] = i->value_; - } - } - - template< class Obj_t, class Map_t > - void map_to_obj( const Map_t& mp_obj, Obj_t& obj ) - { - obj.clear(); - - for( typename Map_t::const_iterator i = mp_obj.begin(); i != mp_obj.end(); ++i ) - { - obj.push_back( typename Obj_t::value_type( i->first, i->second ) ); - } - } - -#ifdef JSON_SPIRIT_VALUE_ENABLED - typedef std::map< std::string, Value > Mapped_obj; -#endif - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - typedef std::map< std::wstring, wValue > wMapped_obj; -#endif - - template< class Object_type, class String_type > - const typename Object_type::value_type::Value_type& find_value( const Object_type& obj, const String_type& name ) - { - for( typename Object_type::const_iterator i = obj.begin(); i != obj.end(); ++i ) - { - if( i->name_ == name ) - { - return i->value_; - } - } - - return Object_type::value_type::Value_type::null; - } -} - -#endif +#ifndef JSON_SPIRIT_UTILS +#define JSON_SPIRIT_UTILS + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include +#include "json5_parser_value.h" + +namespace json5_parser { +template +void obj_to_map(const Obj_t& obj, Map_t& mp_obj) { + mp_obj.clear(); + + for (typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i) { + mp_obj[i->name_] = i->value_; + } +} + +template +void map_to_obj(const Map_t& mp_obj, Obj_t& obj) { + obj.clear(); + + for (typename Map_t::const_iterator i = mp_obj.begin(); i != mp_obj.end(); ++i) { + obj.push_back(typename Obj_t::value_type(i->first, i->second)); + } +} + +#ifdef JSON_SPIRIT_VALUE_ENABLED +typedef std::map Mapped_obj; +#endif + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +typedef std::map wMapped_obj; +#endif + +template +const typename Object_type::value_type::Value_type& find_value( + const Object_type& obj, const String_type& name) { + for (typename Object_type::const_iterator i = obj.begin(); i != obj.end(); ++i) { + if (i->name_ == name) { + return i->value_; + } + } + + return Object_type::value_type::Value_type::null; +} +} // namespace json5_parser + +#endif diff --git a/json5_parser/json5_parser_value.cpp b/json5_parser/json5_parser_value.cpp index e36fb60..be67e15 100644 --- a/json5_parser/json5_parser_value.cpp +++ b/json5_parser/json5_parser_value.cpp @@ -1,6 +1,6 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_value.h" +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_value.h" diff --git a/json5_parser/json5_parser_value.h b/json5_parser/json5_parser_value.h index 0d0a83f..ecb8bd2 100644 --- a/json5_parser/json5_parser_value.h +++ b/json5_parser/json5_parser_value.h @@ -1,605 +1,523 @@ -#ifndef JSON_SPIRIT_VALUE -#define JSON_SPIRIT_VALUE - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// comment out the value types you don't need to reduce build times and intermediate file sizes -#define JSON_SPIRIT_VALUE_ENABLED -#define JSON_SPIRIT_WVALUE_ENABLED -#define JSON_SPIRIT_MVALUE_ENABLED -#define JSON_SPIRIT_WMVALUE_ENABLED - -namespace json5_parser -{ - enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type }; - - static inline std::string value_type_to_string( Value_type vtype ); - - struct Null{}; - - 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 ); - - template< class Iter > - Value_impl( Iter first, Iter last ); // constructor from containers, e.g. std::vector or std::list - - template< BOOST_VARIANT_ENUM_PARAMS( typename T ) > - Value_impl( const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& variant ); // constructor for compatible variant types - - 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: - - void check_type( const Value_type vtype ) const; - - typedef boost::variant< boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >, - String_type, bool, boost::int64_t, double, Null, boost::uint64_t > Variant; - - Variant v_; - - class Variant_converter_visitor : public boost::static_visitor< Variant > - { - public: - - template< typename T, typename A, template< typename, typename > class Cont > - Variant operator()( const Cont< T, A >& cont ) const - { - return Array( cont.begin(), cont.end() ); - } - - Variant operator()( int i ) const - { - return static_cast< boost::int64_t >( i ); - } - - template - Variant operator()( const T& t ) const - { - return t; - } - }; - }; - - // vector objects - - template< class Config > - struct Pair_impl - { - typedef typename Config::String_type String_type; - typedef typename Config::Value_type Value_type; - - Pair_impl() - { - } - - Pair_impl( const String_type& name, const Value_type& value ); - - bool operator==( const Pair_impl& lhs ) const; - - String_type name_; - Value_type value_; - }; - -#if defined( JSON_SPIRIT_VALUE_ENABLED ) || defined( JSON_SPIRIT_WVALUE_ENABLED ) - 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 const String_type& get_name( const Pair_type& pair ) - { - return pair.name_; - } - - static const Value_type& get_value( const Pair_type& pair ) - { - return pair.value_; - } - }; -#endif - - // typedefs for ASCII - -#ifdef JSON_SPIRIT_VALUE_ENABLED - 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; -#endif - - // typedefs for Unicode - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( 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 - -#if defined( JSON_SPIRIT_MVALUE_ENABLED ) || defined( JSON_SPIRIT_WMVALUE_ENABLED ) - 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 std::pair< const String_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 const String_type& get_name( const Pair_type& pair ) - { - return pair.first; - } - - static const Value_type& get_value( const Pair_type& pair ) - { - return pair.second; - } - }; -#endif - - // typedefs for ASCII - -#ifdef JSON_SPIRIT_MVALUE_ENABLED - typedef Config_map< std::string > mConfig; - - typedef mConfig::Value_type mValue; - typedef mConfig::Object_type mObject; - typedef mConfig::Array_type mArray; -#endif - - // typedefs for Unicode - -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( 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 - - inline bool operator==( const Null&, const Null& ) - { - return true; - } - - template< class Config > - const Value_impl< Config > Value_impl< Config >::null; - - template< class Config > - Value_impl< Config >::Value_impl() - : v_( Null() ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const Const_str_ptr value ) - : v_( String_type( value ) ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const String_type& value ) - : v_( value ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const Object& value ) - : v_( value ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const Array& value ) - : v_( value ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( bool value ) - : v_( value ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( int value ) - : v_( static_cast< boost::int64_t >( value ) ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( boost::int64_t value ) - : v_( value ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( boost::uint64_t value ) - : v_( value ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( double value ) - : v_( value ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const Value_impl< Config >& other ) - : v_( other.v_ ) - { - } - - template< class Config > - template< class Iter > - Value_impl< Config >::Value_impl( Iter first, Iter last ) - : v_( Array( first, last ) ) - { - } - - template< class Config > - template< BOOST_VARIANT_ENUM_PARAMS( typename T ) > - Value_impl< Config >::Value_impl( const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& variant ) - : v_( boost::apply_visitor( Variant_converter_visitor(), variant) ) - { - } - - template< class Config > - Value_impl< Config >& Value_impl< Config >::operator=( const Value_impl& lhs ) - { - Value_impl tmp( lhs ); - - std::swap( v_, tmp.v_ ); - - 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; - - return v_ == lhs.v_; - } - - template< class Config > - Value_type Value_impl< Config >::type() const - { - if( is_uint64() ) - { - return int_type; - } - - return static_cast< Value_type >( v_.which() ); - } - - template< class Config > - bool Value_impl< Config >::is_uint64() const - { - return v_.which() == null_type + 1; - } - - template< class Config > - bool Value_impl< Config >::is_null() const - { - return type() == null_type; - } - - template< class Config > - void Value_impl< Config >::check_type( const Value_type vtype ) const - { - if( type() != vtype ) - { - std::ostringstream os; - - os << "get_value< " << value_type_to_string( vtype ) << " > called on " << value_type_to_string( type() ) << " Value"; - - throw std::runtime_error( os.str() ); - } - } - - template< class Config > - const typename Config::String_type& Value_impl< Config >::get_str() const - { - check_type( str_type ); - - return *boost::get< String_type >( &v_ ); - } - - template< class Config > - const typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() const - { - check_type( obj_type ); - - return *boost::get< Object >( &v_ ); - } - - template< class Config > - const typename Value_impl< Config >::Array& Value_impl< Config >::get_array() const - { - check_type( array_type ); - - return *boost::get< Array >( &v_ ); - } - - template< class Config > - bool Value_impl< Config >::get_bool() const - { - check_type( bool_type ); - - return boost::get< bool >( v_ ); - } - - template< class Config > - int Value_impl< Config >::get_int() const - { - check_type( int_type ); - - return static_cast< int >( get_int64() ); - } - - template< class Config > - boost::int64_t Value_impl< Config >::get_int64() const - { - check_type( int_type ); - - if( is_uint64() ) - { - return static_cast< boost::int64_t >( get_uint64() ); - } - - return boost::get< boost::int64_t >( v_ ); - } - - template< class Config > - boost::uint64_t Value_impl< Config >::get_uint64() const - { - check_type( int_type ); - - if( !is_uint64() ) - { - return static_cast< boost::uint64_t >( get_int64() ); - } - - return boost::get< boost::uint64_t >( v_ ); - } - - 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() ); - } - - check_type( real_type ); - - return boost::get< double >( v_ ); - } - - template< class Config > - typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() - { - check_type( obj_type ); - - return *boost::get< Object >( &v_ ); - } - - template< class Config > - typename Value_impl< Config >::Array& Value_impl< Config >::get_array() - { - check_type( array_type ); - - return *boost::get< Array >( &v_ ); - } - - 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 >() ); - } - - static std::string value_type_to_string( const Value_type vtype ) - { - switch( vtype ) - { - case obj_type: return "Object"; - case array_type: return "Array"; - case str_type: return "string"; - case bool_type: return "boolean"; - case int_type: return "integer"; - case real_type: return "real"; - case null_type: return "null"; - } - - assert( false ); - - return "unknown type"; - } -} - -#endif +#ifndef JSON_SPIRIT_VALUE +#define JSON_SPIRIT_VALUE + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// comment out the value types you don't need to reduce build times and intermediate +// file sizes +#define JSON_SPIRIT_VALUE_ENABLED +#define JSON_SPIRIT_WVALUE_ENABLED +#define JSON_SPIRIT_MVALUE_ENABLED +#define JSON_SPIRIT_WMVALUE_ENABLED + +namespace json5_parser { +enum Value_type { + obj_type, + array_type, + str_type, + bool_type, + int_type, + real_type, + null_type +}; + +static inline std::string value_type_to_string(Value_type vtype); + +struct Null {}; + +template // 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); + + template + Value_impl( + Iter first, + Iter last); // constructor from containers, e.g. std::vector or std::list + + template + Value_impl(const boost::variant& + variant); // constructor for compatible variant types + + 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 + 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: + void check_type(const Value_type vtype) const; + + typedef boost::variant, + boost::recursive_wrapper, String_type, bool, + boost::int64_t, double, Null, boost::uint64_t> + Variant; + + Variant v_; + + class Variant_converter_visitor : public boost::static_visitor { + public: + template class Cont> + Variant operator()(const Cont& cont) const { + return Array(cont.begin(), cont.end()); + } + + Variant operator()(int i) const { return static_cast(i); } + + template + Variant operator()(const T& t) const { + return t; + } + }; +}; + +// vector objects + +template +struct Pair_impl { + typedef typename Config::String_type String_type; + typedef typename Config::Value_type Value_type; + + Pair_impl() {} + + Pair_impl(const String_type& name, const Value_type& value); + + bool operator==(const Pair_impl& lhs) const; + + String_type name_; + Value_type value_; +}; + +#if defined(JSON_SPIRIT_VALUE_ENABLED) || defined(JSON_SPIRIT_WVALUE_ENABLED) +template +struct Config_vector { + typedef String String_type; + typedef Value_impl Value_type; + typedef Pair_impl Pair_type; + typedef std::vector Array_type; + typedef std::vector 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 const String_type& get_name(const Pair_type& pair) { return pair.name_; } + + static const Value_type& get_value(const Pair_type& pair) { return pair.value_; } +}; +#endif + +// typedefs for ASCII + +#ifdef JSON_SPIRIT_VALUE_ENABLED +typedef Config_vector Config; + +typedef Config::Value_type Value; +typedef Config::Pair_type Pair; +typedef Config::Object_type Object; +typedef Config::Array_type Array; +#endif + +// typedefs for Unicode + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +typedef Config_vector wConfig; + +typedef wConfig::Value_type wValue; +typedef wConfig::Pair_type wPair; +typedef wConfig::Object_type wObject; +typedef wConfig::Array_type wArray; +#endif + +// map objects + +#if defined(JSON_SPIRIT_MVALUE_ENABLED) || defined(JSON_SPIRIT_WMVALUE_ENABLED) +template +struct Config_map { + typedef String String_type; + typedef Value_impl Value_type; + typedef std::vector Array_type; + typedef std::map Object_type; + typedef std::pair Pair_type; + + static Value_type& add(Object_type& obj, const String_type& name, + const Value_type& value) { + return obj[name] = value; + } + + static const String_type& get_name(const Pair_type& pair) { return pair.first; } + + static const Value_type& get_value(const Pair_type& pair) { return pair.second; } +}; +#endif + +// typedefs for ASCII + +#ifdef JSON_SPIRIT_MVALUE_ENABLED +typedef Config_map mConfig; + +typedef mConfig::Value_type mValue; +typedef mConfig::Object_type mObject; +typedef mConfig::Array_type mArray; +#endif + +// typedefs for Unicode + +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +typedef Config_map wmConfig; + +typedef wmConfig::Value_type wmValue; +typedef wmConfig::Object_type wmObject; +typedef wmConfig::Array_type wmArray; +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +// implementation + +inline bool operator==(const Null&, const Null&) { return true; } + +template +const Value_impl Value_impl::null; + +template +Value_impl::Value_impl() : v_(Null()) {} + +template +Value_impl::Value_impl(const Const_str_ptr value) : v_(String_type(value)) {} + +template +Value_impl::Value_impl(const String_type& value) : v_(value) {} + +template +Value_impl::Value_impl(const Object& value) : v_(value) {} + +template +Value_impl::Value_impl(const Array& value) : v_(value) {} + +template +Value_impl::Value_impl(bool value) : v_(value) {} + +template +Value_impl::Value_impl(int value) : v_(static_cast(value)) {} + +template +Value_impl::Value_impl(boost::int64_t value) : v_(value) {} + +template +Value_impl::Value_impl(boost::uint64_t value) : v_(value) {} + +template +Value_impl::Value_impl(double value) : v_(value) {} + +template +Value_impl::Value_impl(const Value_impl& other) : v_(other.v_) {} + +template +template +Value_impl::Value_impl(Iter first, Iter last) : v_(Array(first, last)) {} + +template +template +Value_impl::Value_impl( + const boost::variant& variant) + : v_(boost::apply_visitor(Variant_converter_visitor(), variant)) {} + +template +Value_impl& Value_impl::operator=(const Value_impl& lhs) { + Value_impl tmp(lhs); + + std::swap(v_, tmp.v_); + + return *this; +} + +template +bool Value_impl::operator==(const Value_impl& lhs) const { + if (this == &lhs) return true; + + if (type() != lhs.type()) return false; + + return v_ == lhs.v_; +} + +template +Value_type Value_impl::type() const { + if (is_uint64()) { + return int_type; + } + + return static_cast(v_.which()); +} + +template +bool Value_impl::is_uint64() const { + return v_.which() == null_type + 1; +} + +template +bool Value_impl::is_null() const { + return type() == null_type; +} + +template +void Value_impl::check_type(const Value_type vtype) const { + if (type() != vtype) { + std::ostringstream os; + + os << "get_value< " << value_type_to_string(vtype) << " > called on " + << value_type_to_string(type()) << " Value"; + + throw std::runtime_error(os.str()); + } +} + +template +const typename Config::String_type& Value_impl::get_str() const { + check_type(str_type); + + return *boost::get(&v_); +} + +template +const typename Value_impl::Object& Value_impl::get_obj() const { + check_type(obj_type); + + return *boost::get(&v_); +} + +template +const typename Value_impl::Array& Value_impl::get_array() const { + check_type(array_type); + + return *boost::get(&v_); +} + +template +bool Value_impl::get_bool() const { + check_type(bool_type); + + return boost::get(v_); +} + +template +int Value_impl::get_int() const { + check_type(int_type); + + return static_cast(get_int64()); +} + +template +boost::int64_t Value_impl::get_int64() const { + check_type(int_type); + + if (is_uint64()) { + return static_cast(get_uint64()); + } + + return boost::get(v_); +} + +template +boost::uint64_t Value_impl::get_uint64() const { + check_type(int_type); + + if (!is_uint64()) { + return static_cast(get_int64()); + } + + return boost::get(v_); +} + +template +double Value_impl::get_real() const { + if (type() == int_type) { + return is_uint64() ? static_cast(get_uint64()) + : static_cast(get_int64()); + } + + check_type(real_type); + + return boost::get(v_); +} + +template +typename Value_impl::Object& Value_impl::get_obj() { + check_type(obj_type); + + return *boost::get(&v_); +} + +template +typename Value_impl::Array& Value_impl::get_array() { + check_type(array_type); + + return *boost::get(&v_); +} + +template +Pair_impl::Pair_impl(const String_type& name, const Value_type& value) + : name_(name), value_(value) {} + +template +bool Pair_impl::operator==(const Pair_impl& 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 +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 +struct Type_to_type {}; + +template +int get_value(const Value& value, Type_to_type) { + return value.get_int(); +} + +template +boost::int64_t get_value(const Value& value, Type_to_type) { + return value.get_int64(); +} + +template +boost::uint64_t get_value(const Value& value, Type_to_type) { + return value.get_uint64(); +} + +template +double get_value(const Value& value, Type_to_type) { + return value.get_real(); +} + +template +typename Value::String_type get_value(const Value& value, + Type_to_type) { + return value.get_str(); +} + +template +typename Value::Array get_value(const Value& value, + Type_to_type) { + return value.get_array(); +} + +template +typename Value::Object get_value(const Value& value, + Type_to_type) { + return value.get_obj(); +} + +template +bool get_value(const Value& value, Type_to_type) { + return value.get_bool(); +} +} // namespace internal_ + +template +template +T Value_impl::get_value() const { + return internal_::get_value(*this, internal_::Type_to_type()); +} + +static std::string value_type_to_string(const Value_type vtype) { + switch (vtype) { + case obj_type: + return "Object"; + case array_type: + return "Array"; + case str_type: + return "string"; + case bool_type: + return "boolean"; + case int_type: + return "integer"; + case real_type: + return "real"; + case null_type: + return "null"; + } + + assert(false); + + return "unknown type"; +} +} // namespace json5_parser + +#endif diff --git a/json5_parser/json5_parser_writer.cpp b/json5_parser/json5_parser_writer.cpp index 9345986..88d2061 100644 --- a/json5_parser/json5_parser_writer.cpp +++ b/json5_parser/json5_parser_writer.cpp @@ -1,96 +1,96 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_writer.h" -#include "json5_parser_writer_template.h" - -using namespace json5_parser; - -#ifdef JSON_SPIRIT_VALUE_ENABLED - void json5_parser::write( const Value& value, std::ostream& os, int options, unsigned int precision_of_doubles ) - { - write_stream( value, os, options, precision_of_doubles ); - } - std::string json5_parser::write( const Value& value, int options, unsigned int precision_of_doubles ) - { - return write_string( value, options, precision_of_doubles ); - } - - void json5_parser::write_formatted( const Value& value, std::ostream& os, unsigned int precision_of_doubles ) - { - write_stream( value, os, pretty_print, precision_of_doubles ); - } - - std::string json5_parser::write_formatted( const Value& value, unsigned int precision_of_doubles ) - { - return write_string( value, pretty_print, precision_of_doubles ); - } -#endif - -#ifdef JSON_SPIRIT_MVALUE_ENABLED - void json5_parser::write( const mValue& value, std::ostream& os, int options, unsigned int precision_of_doubles ) - { - write_stream( value, os, options, precision_of_doubles ); - } - - std::string json5_parser::write( const mValue& value, int options, unsigned int precision_of_doubles ) - { - return write_string( value, options, precision_of_doubles ); - } - - void json5_parser::write_formatted( const mValue& value, std::ostream& os, unsigned int precision_of_doubles ) - { - write_stream( value, os, pretty_print, precision_of_doubles ); - } - - std::string json5_parser::write_formatted( const mValue& value, unsigned int precision_of_doubles ) - { - return write_string( value, pretty_print, precision_of_doubles ); - } -#endif - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void json5_parser::write( const wValue& value, std::wostream& os, int options, unsigned int precision_of_doubles ) - { - write_stream( value, os, options, precision_of_doubles ); - } - - std::wstring json5_parser::write( const wValue& value, int options, unsigned int precision_of_doubles ) - { - return write_string( value, options, precision_of_doubles ); - } - - void json5_parser::write_formatted( const wValue& value, std::wostream& os, unsigned int precision_of_doubles ) - { - write_stream( value, os, pretty_print, precision_of_doubles ); - } - - std::wstring json5_parser::write_formatted( const wValue& value, unsigned int precision_of_doubles ) - { - return write_string( value, pretty_print, precision_of_doubles ); - } -#endif - -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void json5_parser::write_formatted( const wmValue& value, std::wostream& os, unsigned int precision_of_doubles ) - { - write_stream( value, os, pretty_print, precision_of_doubles ); - } - - std::wstring json5_parser::write_formatted( const wmValue& value, unsigned int precision_of_doubles ) - { - return write_string( value, pretty_print, precision_of_doubles ); - } - - void json5_parser::write( const wmValue& value, std::wostream& os, int options, unsigned int precision_of_doubles ) - { - write_stream( value, os, options, precision_of_doubles ); - } - - std::wstring json5_parser::write( const wmValue& value, int options, unsigned int precision_of_doubles ) - { - return write_string( value, options, precision_of_doubles ); - } -#endif +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_writer.h" +#include "json5_parser_writer_template.h" + +using namespace json5_parser; + +#ifdef JSON_SPIRIT_VALUE_ENABLED +void json5_parser::write(const Value& value, std::ostream& os, int options, + unsigned int precision_of_doubles) { + write_stream(value, os, options, precision_of_doubles); +} +std::string json5_parser::write(const Value& value, int options, + unsigned int precision_of_doubles) { + return write_string(value, options, precision_of_doubles); +} + +void json5_parser::write_formatted(const Value& value, std::ostream& os, + unsigned int precision_of_doubles) { + write_stream(value, os, pretty_print, precision_of_doubles); +} + +std::string json5_parser::write_formatted(const Value& value, + unsigned int precision_of_doubles) { + return write_string(value, pretty_print, precision_of_doubles); +} +#endif + +#ifdef JSON_SPIRIT_MVALUE_ENABLED +void json5_parser::write(const mValue& value, std::ostream& os, int options, + unsigned int precision_of_doubles) { + write_stream(value, os, options, precision_of_doubles); +} + +std::string json5_parser::write(const mValue& value, int options, + unsigned int precision_of_doubles) { + return write_string(value, options, precision_of_doubles); +} + +void json5_parser::write_formatted(const mValue& value, std::ostream& os, + unsigned int precision_of_doubles) { + write_stream(value, os, pretty_print, precision_of_doubles); +} + +std::string json5_parser::write_formatted(const mValue& value, + unsigned int precision_of_doubles) { + return write_string(value, pretty_print, precision_of_doubles); +} +#endif + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void json5_parser::write(const wValue& value, std::wostream& os, int options, + unsigned int precision_of_doubles) { + write_stream(value, os, options, precision_of_doubles); +} + +std::wstring json5_parser::write(const wValue& value, int options, + unsigned int precision_of_doubles) { + return write_string(value, options, precision_of_doubles); +} + +void json5_parser::write_formatted(const wValue& value, std::wostream& os, + unsigned int precision_of_doubles) { + write_stream(value, os, pretty_print, precision_of_doubles); +} + +std::wstring json5_parser::write_formatted(const wValue& value, + unsigned int precision_of_doubles) { + return write_string(value, pretty_print, precision_of_doubles); +} +#endif + +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void json5_parser::write_formatted(const wmValue& value, std::wostream& os, + unsigned int precision_of_doubles) { + write_stream(value, os, pretty_print, precision_of_doubles); +} + +std::wstring json5_parser::write_formatted(const wmValue& value, + unsigned int precision_of_doubles) { + return write_string(value, pretty_print, precision_of_doubles); +} + +void json5_parser::write(const wmValue& value, std::wostream& os, int options, + unsigned int precision_of_doubles) { + write_stream(value, os, options, precision_of_doubles); +} + +std::wstring json5_parser::write(const wmValue& value, int options, + unsigned int precision_of_doubles) { + return write_string(value, options, precision_of_doubles); +} +#endif diff --git a/json5_parser/json5_parser_writer.h b/json5_parser/json5_parser_writer.h index 48874b8..8850067 100644 --- a/json5_parser/json5_parser_writer.h +++ b/json5_parser/json5_parser_writer.h @@ -1,65 +1,78 @@ -#ifndef JSON_SPIRIT_WRITER -#define JSON_SPIRIT_WRITER - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json5_parser_value.h" -#include "json5_parser_writer_options.h" -#include - -namespace json5_parser -{ - // these functions to convert JSON Values to text - // note the precision used outputing doubles defaults to 17, - // unless the remove_trailing_zeros option is given in which case the default is 16 - -#ifdef JSON_SPIRIT_VALUE_ENABLED - void write( const Value& value, std::ostream& os, int options = none, unsigned int precision_of_doubles = 0 ); - std::string write( const Value& value, int options = none, unsigned int precision_of_doubles = 0 ); -#endif - -#ifdef JSON_SPIRIT_MVALUE_ENABLED - void write( const mValue& value, std::ostream& os, int options = none, unsigned int precision_of_doubles = 0 ); - std::string write( const mValue& value, int options = none, unsigned int precision_of_doubles = 0 ); -#endif - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void write( const wValue& value, std::wostream& os, int options = none, unsigned int precision_of_doubles = 0 ); - std::wstring write( const wValue& value, int options = none, unsigned int precision_of_doubles = 0 ); -#endif - -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void write( const wmValue& value, std::wostream& os, int options = none, unsigned int precision_of_doubles = 0 ); - std::wstring write( const wmValue& value, int options = none, unsigned int precision_of_doubles = 0 ); -#endif - - // these "formatted" versions of the "write" functions are the equivalent of the above functions - // with option "pretty_print" - -#ifdef JSON_SPIRIT_VALUE_ENABLED - void write_formatted( const Value& value, std::ostream& os, unsigned int precision_of_doubles = 0 ); - std::string write_formatted( const Value& value, unsigned int precision_of_doubles = 0 ); -#endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED - void write_formatted( const mValue& value, std::ostream& os, unsigned int precision_of_doubles = 0 ); - std::string write_formatted( const mValue& value, unsigned int precision_of_doubles = 0 ); -#endif - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void write_formatted( const wValue& value, std::wostream& os, unsigned int precision_of_doubles = 0 ); - std::wstring write_formatted( const wValue& value, unsigned int precision_of_doubles = 0 ); -#endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void write_formatted( const wmValue& value, std::wostream& os, unsigned int precision_of_doubles = 0 ); - std::wstring write_formatted( const wmValue& value, unsigned int precision_of_doubles = 0 ); -#endif -} - -#endif +#ifndef JSON_SPIRIT_WRITER +#define JSON_SPIRIT_WRITER + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include +#include "json5_parser_value.h" +#include "json5_parser_writer_options.h" + +namespace json5_parser { +// these functions to convert JSON Values to text +// note the precision used outputing doubles defaults to 17, +// unless the remove_trailing_zeros option is given in which case the default is 16 + +#ifdef JSON_SPIRIT_VALUE_ENABLED +void write(const Value& value, std::ostream& os, int options = none, + unsigned int precision_of_doubles = 0); +std::string write(const Value& value, int options = none, + unsigned int precision_of_doubles = 0); +#endif + +#ifdef JSON_SPIRIT_MVALUE_ENABLED +void write(const mValue& value, std::ostream& os, int options = none, + unsigned int precision_of_doubles = 0); +std::string write(const mValue& value, int options = none, + unsigned int precision_of_doubles = 0); +#endif + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void write(const wValue& value, std::wostream& os, int options = none, + unsigned int precision_of_doubles = 0); +std::wstring write(const wValue& value, int options = none, + unsigned int precision_of_doubles = 0); +#endif + +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void write(const wmValue& value, std::wostream& os, int options = none, + unsigned int precision_of_doubles = 0); +std::wstring write(const wmValue& value, int options = none, + unsigned int precision_of_doubles = 0); +#endif + +// these "formatted" versions of the "write" functions are the equivalent of the above +// functions with option "pretty_print" + +#ifdef JSON_SPIRIT_VALUE_ENABLED +void write_formatted(const Value& value, std::ostream& os, + unsigned int precision_of_doubles = 0); +std::string write_formatted(const Value& value, unsigned int precision_of_doubles = 0); +#endif +#ifdef JSON_SPIRIT_MVALUE_ENABLED +void write_formatted(const mValue& value, std::ostream& os, + unsigned int precision_of_doubles = 0); +std::string write_formatted(const mValue& value, unsigned int precision_of_doubles = 0); +#endif + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void write_formatted(const wValue& value, std::wostream& os, + unsigned int precision_of_doubles = 0); +std::wstring write_formatted(const wValue& value, + unsigned int precision_of_doubles = 0); +#endif +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void write_formatted(const wmValue& value, std::wostream& os, + unsigned int precision_of_doubles = 0); +std::wstring write_formatted(const wmValue& value, + unsigned int precision_of_doubles = 0); +#endif +} // namespace json5_parser + +#endif diff --git a/json5_parser/json5_parser_writer_options.h b/json5_parser/json5_parser_writer_options.h index 374db46..f858ae2 100644 --- a/json5_parser/json5_parser_writer_options.h +++ b/json5_parser/json5_parser_writer_options.h @@ -1,35 +1,36 @@ -#ifndef JSON_SPIRIT_WRITER_OPTIONS -#define JSON_SPIRIT_WRITER_OPTIONS - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -namespace json5_parser -{ - enum Output_options{ none = 0, // default options - - pretty_print = 0x01, // Add whitespace to format the output nicely. - - raw_utf8 = 0x02, // This prevents non-printable characters from being escapted using "\uNNNN" notation. - // Note, this is an extension to the JSON standard. It disables the escaping of - // non-printable characters allowing UTF-8 sequences held in 8 bit char strings - // to pass through unaltered. - - remove_trailing_zeros = 0x04, - // no longer used kept for backwards compatibility - single_line_arrays = 0x08, - // pretty printing except that arrays printed on single lines unless they contain - // composite elements, i.e. objects or arrays - always_escape_nonascii = 0x10, - // all unicode wide characters are escaped, i.e. outputed as "\uXXXX", even if they are - // printable under the current locale, ascii printable chars are not escaped - }; -} - -#endif +#ifndef JSON_SPIRIT_WRITER_OPTIONS +#define JSON_SPIRIT_WRITER_OPTIONS + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +namespace json5_parser { +enum Output_options { + none = 0, // default options + + pretty_print = 0x01, // Add whitespace to format the output nicely. + + raw_utf8 = 0x02, // This prevents non-printable characters from being escapted + // using "\uNNNN" notation. Note, this is an extension to the JSON + // standard. It disables the escaping of non-printable characters + // allowing UTF-8 sequences held in 8 bit char strings to pass + // through unaltered. + + remove_trailing_zeros = 0x04, + // no longer used kept for backwards compatibility + single_line_arrays = 0x08, + // pretty printing except that arrays printed on single lines unless they contain + // composite elements, i.e. objects or arrays + always_escape_nonascii = 0x10, + // all unicode wide characters are escaped, i.e. outputed as "\uXXXX", even if they + // are printable under the current locale, ascii printable chars are not escaped +}; +} + +#endif diff --git a/json5_parser/json5_parser_writer_template.h b/json5_parser/json5_parser_writer_template.h index b9ab62e..23aada9 100644 --- a/json5_parser/json5_parser_writer_template.h +++ b/json5_parser/json5_parser_writer_template.h @@ -1,325 +1,315 @@ -#ifndef JSON_SPIRIT_WRITER_TEMPLATE -#define JSON_SPIRIT_WRITER_TEMPLATE - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json5_parser_value.h" -#include "json5_parser_writer_options.h" - -#include -#include -#include -#include - -namespace json5_parser -{ - inline char to_hex_char( unsigned int c ) - { - assert( c <= 0xF ); - - const char ch = static_cast< char >( c ); - - if( ch < 10 ) return '0' + ch; - - return 'A' - 10 + ch; - } - - template< class String_type > - String_type non_printable_to_string( unsigned int c ) - { - String_type result( 6, '\\' ); - - result[1] = 'u'; - - result[ 5 ] = to_hex_char( c & 0x000F ); c >>= 4; - result[ 4 ] = to_hex_char( c & 0x000F ); c >>= 4; - result[ 3 ] = to_hex_char( c & 0x000F ); c >>= 4; - result[ 2 ] = to_hex_char( c & 0x000F ); - - return result; - } - - template< typename Char_type, class String_type > - bool add_esc_char( Char_type c, String_type& s ) - { - switch( c ) - { - case '"': s += to_str< String_type >( "\\\"" ); return true; - case '\\': s += to_str< String_type >( "\\\\" ); return true; - case '\b': s += to_str< String_type >( "\\b" ); return true; - case '\f': s += to_str< String_type >( "\\f" ); return true; - case '\n': s += to_str< String_type >( "\\n" ); return true; - case '\r': s += to_str< String_type >( "\\r" ); return true; - case '\t': s += to_str< String_type >( "\\t" ); return true; - } - - return false; - } - - template< class String_type > - String_type add_esc_chars( const String_type& s, bool raw_utf8, bool esc_nonascii ) - { - typedef typename String_type::const_iterator Iter_type; - typedef typename String_type::value_type Char_type; - - String_type result; - - const Iter_type end( s.end() ); - - for( Iter_type i = s.begin(); i != end; ++i ) - { - const Char_type c( *i ); - - if( add_esc_char( c, result ) ) continue; - - if( raw_utf8 ) - { - result += c; - } - else - { - const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c ); - - if( !esc_nonascii && iswprint( unsigned_c ) ) - { - result += c; - } - else - { - result += non_printable_to_string< String_type >( unsigned_c ); - } - } - } - - return result; - } - - // this class generates the JSON text, - // it keeps track of the indentation level etc. - // - template< class Value_type, class Ostream_type > - class Generator - { - typedef typename Value_type::Config_type Config_type; - typedef typename Config_type::String_type String_type; - typedef typename Config_type::Object_type Object_type; - typedef typename Config_type::Array_type Array_type; - typedef typename String_type::value_type Char_type; - typedef typename Object_type::value_type Obj_member_type; - - public: - - Generator( const Value_type& value, Ostream_type& os, int options, unsigned int precision_of_doubles ) - : os_( os ) - , indentation_level_( 0 ) - , pretty_( ( options & pretty_print ) != 0 || ( options & single_line_arrays ) != 0 ) - , raw_utf8_( ( options & raw_utf8 ) != 0 ) - , esc_nonascii_( ( options & always_escape_nonascii ) != 0 ) - , single_line_arrays_( ( options & single_line_arrays ) != 0 ) - , ios_saver_( os ) - { - if( precision_of_doubles > 0 ) - { - precision_of_doubles_ = precision_of_doubles; - } - else - { - precision_of_doubles_ = ( options & remove_trailing_zeros ) != 0 ? 16 : 17; - } - - output( value ); - } - - private: - - void output( const Value_type& value ) - { - switch( value.type() ) - { - case obj_type: output( value.get_obj() ); break; - case array_type: output( value.get_array() ); break; - case str_type: output( value.get_str() ); break; - case bool_type: output( value.get_bool() ); break; - case real_type: output( value.get_real() ); break; - case int_type: output_int( value ); break; - case null_type: os_ << "null"; break; - default: assert( false ); - } - } - - void output( const Object_type& obj ) - { - output_array_or_obj( obj, '{', '}' ); - } - - void output( const Obj_member_type& member ) - { - output( Config_type::get_name( member ) ); space(); - os_ << ':'; space(); - output( Config_type::get_value( member ) ); - } - - void output_int( const Value_type& value ) - { - if( value.is_uint64() ) - { - os_ << value.get_uint64(); - } - else - { - os_ << value.get_int64(); - } - } - - void output( const String_type& s ) - { - os_ << '"' << add_esc_chars( s, raw_utf8_, esc_nonascii_ ) << '"'; - } - - void output( bool b ) - { - os_ << to_str< String_type >( b ? "true" : "false" ); - } - - void output( double d ) - { - os_ << std::setprecision( precision_of_doubles_ ) << d; - } - - static bool contains_composite_elements( const Array_type& arr ) - { - for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i ) - { - const Value_type& val = *i; - - if( val.type() == obj_type || - val.type() == array_type ) - { - return true; - } - } - - return false; - } - - template< class Iter > - void output_composite_item( Iter i, Iter last ) - { - output( *i ); - - if( ++i != last ) - { - os_ << ','; - } - } - - void output( const Array_type& arr ) - { - if( single_line_arrays_ && !contains_composite_elements( arr ) ) - { - os_ << '['; space(); - - for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i ) - { - output_composite_item( i, arr.end() ); - - space(); - } - - os_ << ']'; - } - else - { - output_array_or_obj( arr, '[', ']' ); - } - } - - template< class T > - void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char ) - { - os_ << start_char; new_line(); - - ++indentation_level_; - - for( typename T::const_iterator i = t.begin(); i != t.end(); ++i ) - { - indent(); - - output_composite_item( i, t.end() ); - - new_line(); - } - - --indentation_level_; - - indent(); os_ << end_char; - } - - void indent() - { - if( !pretty_ ) return; - - for( int i = 0; i < indentation_level_; ++i ) - { - os_ << " "; - } - } - - void space() - { - if( pretty_ ) os_ << ' '; - } - - void new_line() - { - if( pretty_ ) os_ << '\n'; - } - - Generator& operator=( const Generator& ); // to prevent "assignment operator could not be generated" warning - - Ostream_type& os_; - int indentation_level_; - bool pretty_; - bool raw_utf8_; - bool esc_nonascii_; - bool single_line_arrays_; - int precision_of_doubles_; - boost::io::basic_ios_all_saver< Char_type > ios_saver_; // so that ostream state is reset after control is returned to the caller - }; - - // writes JSON Value to a stream, e.g. - // - // write_stream( value, os, pretty_print ); - // - template< class Value_type, class Ostream_type > - void write_stream( const Value_type& value, Ostream_type& os, int options = none, unsigned int precision_of_doubles = 0 ) - { - os << std::dec; - Generator< Value_type, Ostream_type >( value, os, options, precision_of_doubles ); - } - - // writes JSON Value to a stream, e.g. - // - // const string json_str = write( value, pretty_print ); - // - template< class Value_type > - typename Value_type::String_type write_string( const Value_type& value, int options = none, unsigned int precision_of_doubles = 0 ) - { - typedef typename Value_type::String_type::value_type Char_type; - - std::basic_ostringstream< Char_type > os; - - write_stream( value, os, options, precision_of_doubles ); - - return os.str(); - } -} - -#endif +#ifndef JSON_SPIRIT_WRITER_TEMPLATE +#define JSON_SPIRIT_WRITER_TEMPLATE + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "json5_parser_value.h" +#include "json5_parser_writer_options.h" + +#include +#include +#include +#include + +namespace json5_parser { +inline char to_hex_char(unsigned int c) { + assert(c <= 0xF); + + const char ch = static_cast(c); + + if (ch < 10) return '0' + ch; + + return 'A' - 10 + ch; +} + +template +String_type non_printable_to_string(unsigned int c) { + String_type result(6, '\\'); + + result[1] = 'u'; + + result[5] = to_hex_char(c & 0x000F); + c >>= 4; + result[4] = to_hex_char(c & 0x000F); + c >>= 4; + result[3] = to_hex_char(c & 0x000F); + c >>= 4; + result[2] = to_hex_char(c & 0x000F); + + return result; +} + +template +bool add_esc_char(Char_type c, String_type& s) { + switch (c) { + case '"': + s += to_str("\\\""); + return true; + case '\\': + s += to_str("\\\\"); + return true; + case '\b': + s += to_str("\\b"); + return true; + case '\f': + s += to_str("\\f"); + return true; + case '\n': + s += to_str("\\n"); + return true; + case '\r': + s += to_str("\\r"); + return true; + case '\t': + s += to_str("\\t"); + return true; + } + + return false; +} + +template +String_type add_esc_chars(const String_type& s, bool raw_utf8, bool esc_nonascii) { + typedef typename String_type::const_iterator Iter_type; + typedef typename String_type::value_type Char_type; + + String_type result; + + const Iter_type end(s.end()); + + for (Iter_type i = s.begin(); i != end; ++i) { + const Char_type c(*i); + + if (add_esc_char(c, result)) continue; + + if (raw_utf8) { + result += c; + } else { + const wint_t unsigned_c((c >= 0) ? c : 256 + c); + + if (!esc_nonascii && iswprint(unsigned_c)) { + result += c; + } else { + result += non_printable_to_string(unsigned_c); + } + } + } + + return result; +} + +// this class generates the JSON text, +// it keeps track of the indentation level etc. +// +template +class Generator { + typedef typename Value_type::Config_type Config_type; + typedef typename Config_type::String_type String_type; + typedef typename Config_type::Object_type Object_type; + typedef typename Config_type::Array_type Array_type; + typedef typename String_type::value_type Char_type; + typedef typename Object_type::value_type Obj_member_type; + +public: + Generator(const Value_type& value, Ostream_type& os, int options, + unsigned int precision_of_doubles) + : os_(os), + indentation_level_(0), + pretty_((options & pretty_print) != 0 || + (options & single_line_arrays) != 0), + raw_utf8_((options & raw_utf8) != 0), + esc_nonascii_((options & always_escape_nonascii) != 0), + single_line_arrays_((options & single_line_arrays) != 0), + ios_saver_(os) { + if (precision_of_doubles > 0) { + precision_of_doubles_ = precision_of_doubles; + } else { + precision_of_doubles_ = (options & remove_trailing_zeros) != 0 ? 16 : 17; + } + + output(value); + } + +private: + void output(const Value_type& value) { + switch (value.type()) { + case obj_type: + output(value.get_obj()); + break; + case array_type: + output(value.get_array()); + break; + case str_type: + output(value.get_str()); + break; + case bool_type: + output(value.get_bool()); + break; + case real_type: + output(value.get_real()); + break; + case int_type: + output_int(value); + break; + case null_type: + os_ << "null"; + break; + default: + assert(false); + } + } + + void output(const Object_type& obj) { output_array_or_obj(obj, '{', '}'); } + + void output(const Obj_member_type& member) { + output(Config_type::get_name(member)); + space(); + os_ << ':'; + space(); + output(Config_type::get_value(member)); + } + + void output_int(const Value_type& value) { + if (value.is_uint64()) { + os_ << value.get_uint64(); + } else { + os_ << value.get_int64(); + } + } + + void output(const String_type& s) { + os_ << '"' << add_esc_chars(s, raw_utf8_, esc_nonascii_) << '"'; + } + + void output(bool b) { os_ << to_str(b ? "true" : "false"); } + + void output(double d) { os_ << std::setprecision(precision_of_doubles_) << d; } + + static bool contains_composite_elements(const Array_type& arr) { + for (typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i) { + const Value_type& val = *i; + + if (val.type() == obj_type || val.type() == array_type) { + return true; + } + } + + return false; + } + + template + void output_composite_item(Iter i, Iter last) { + output(*i); + + if (++i != last) { + os_ << ','; + } + } + + void output(const Array_type& arr) { + if (single_line_arrays_ && !contains_composite_elements(arr)) { + os_ << '['; + space(); + + for (typename Array_type::const_iterator i = arr.begin(); i != arr.end(); + ++i) { + output_composite_item(i, arr.end()); + + space(); + } + + os_ << ']'; + } else { + output_array_or_obj(arr, '[', ']'); + } + } + + template + void output_array_or_obj(const T& t, Char_type start_char, Char_type end_char) { + os_ << start_char; + new_line(); + + ++indentation_level_; + + for (typename T::const_iterator i = t.begin(); i != t.end(); ++i) { + indent(); + + output_composite_item(i, t.end()); + + new_line(); + } + + --indentation_level_; + + indent(); + os_ << end_char; + } + + void indent() { + if (!pretty_) return; + + for (int i = 0; i < indentation_level_; ++i) { + os_ << " "; + } + } + + void space() { + if (pretty_) os_ << ' '; + } + + void new_line() { + if (pretty_) os_ << '\n'; + } + + Generator& operator=(const Generator&); // to prevent "assignment operator could + // not be generated" warning + + Ostream_type& os_; + int indentation_level_; + bool pretty_; + bool raw_utf8_; + bool esc_nonascii_; + bool single_line_arrays_; + int precision_of_doubles_; + boost::io::basic_ios_all_saver ios_saver_; // so that ostream state is + // reset after control is + // returned to the caller +}; + +// writes JSON Value to a stream, e.g. +// +// write_stream( value, os, pretty_print ); +// +template +void write_stream(const Value_type& value, Ostream_type& os, int options = none, + unsigned int precision_of_doubles = 0) { + os << std::dec; + Generator(value, os, options, precision_of_doubles); +} + +// writes JSON Value to a stream, e.g. +// +// const string json_str = write( value, pretty_print ); +// +template +typename Value_type::String_type write_string(const Value_type& value, + int options = none, + unsigned int precision_of_doubles = 0) { + typedef typename Value_type::String_type::value_type Char_type; + + std::basic_ostringstream os; + + write_stream(value, os, options, precision_of_doubles); + + return os.str(); +} +} // namespace json5_parser + +#endif diff --git a/json_demo/json_demo.cpp b/json_demo/json_demo.cpp index d1ffed7..14fcc36 100644 --- a/json_demo/json_demo.cpp +++ b/json_demo/json_demo.cpp @@ -1,149 +1,128 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -// This demo shows you how to read and write JSON objects and arrays. -// In this demo objects are stored as a vector of name/value pairs. - -#include "json5_parser.h" -#include -#include - -#ifndef JSON_SPIRIT_VALUE_ENABLED -#error Please define JSON_SPIRIT_VALUE_ENABLED for the Value type to be enabled -#endif - -using namespace std; -using namespace json5_parser; - -struct Address -{ - int house_number_; - string road_; - string town_; - string county_; - string country_; -}; - -bool operator==( const Address& a1, const Address& a2 ) -{ - return ( a1.house_number_ == a2.house_number_ ) && - ( a1.road_ == a2.road_ ) && - ( a1.town_ == a2.town_ ) && - ( a1.county_ == a2.county_ ) && - ( a1.country_ == a2.country_ ); -} - -void write_address( Array& a, const Address& addr ) -{ - Object addr_obj; - - addr_obj.push_back( Pair( "house_number", addr.house_number_ ) ); - addr_obj.push_back( Pair( "road", addr.road_ ) ); - addr_obj.push_back( Pair( "town", addr.town_ ) ); - addr_obj.push_back( Pair( "county", addr.county_ ) ); - addr_obj.push_back( Pair( "country", addr.country_ ) ); - - a.push_back( addr_obj ); -} - -Address read_address( const Object& obj ) -{ - Address addr; - - for( Object::size_type i = 0; i != obj.size(); ++i ) - { - const Pair& pair = obj[i]; - - const string& name = pair.name_; - const Value& value = pair.value_; - - if( name == "house_number" ) - { - addr.house_number_ = value.get_int(); - } - else if( name == "road" ) - { - addr.road_ = value.get_str(); - } - else if( name == "town" ) - { - addr.town_ = value.get_str(); - } - else if( name == "county" ) - { - addr.county_ = value.get_str(); - } - else if( name == "country" ) - { - addr.country_ = value.get_str(); - } - else - { - assert( false ); - } - } - - return addr; -} - -void write_addrs( const char* file_name, const Address addrs[] ) -{ - Array addr_array; - - for( int i = 0; i < 5; ++i ) - { - write_address( addr_array, addrs[i] ); - } - - ofstream os( file_name ); - - write_formatted( addr_array, os ); - - os.close(); -} - -vector< Address > read_addrs( const char* file_name ) -{ - ifstream is( file_name ); - - Value value; - - read( is, value ); - - const Array& addr_array = value.get_array(); - - vector< Address > addrs; - - for( unsigned int i = 0; i < addr_array.size(); ++i ) - { - addrs.push_back( read_address( addr_array[i].get_obj() ) ); - } - - return addrs; -} - -int main() -{ - const Address addrs[5] = { { 42, "East Street", "Newtown", "Essex", "England" }, - { 1, "West Street", "Hull", "Yorkshire", "England" }, - { 12, "South Road", "Aberystwyth", "Dyfed", "Wales" }, - { 45, "North Road", "Paignton", "Devon", "England" }, - { 78, "Upper Street", "Ware", "Hertfordshire", "England" } }; - - const char* file_name( "demo.txt" ); - - write_addrs( file_name, addrs ); - - vector< Address > new_addrs = read_addrs( file_name ); - - assert( new_addrs.size() == 5 ); - - for( int i = 0; i < 5; ++i ) - { - assert( new_addrs[i] == addrs[i] ); - } - - return 0; -} +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +// This demo shows you how to read and write JSON objects and arrays. +// In this demo objects are stored as a vector of name/value pairs. + +#include +#include + +#include "json5_parser.h" + +#ifndef JSON_SPIRIT_VALUE_ENABLED +#error Please define JSON_SPIRIT_VALUE_ENABLED for the Value type to be enabled +#endif + +using namespace std; +using namespace json5_parser; + +struct Address { + int house_number_; + string road_; + string town_; + string county_; + string country_; +}; + +bool operator==(const Address& a1, const Address& a2) { + return (a1.house_number_ == a2.house_number_) && (a1.road_ == a2.road_) && + (a1.town_ == a2.town_) && (a1.county_ == a2.county_) && + (a1.country_ == a2.country_); +} + +void write_address(Array& a, const Address& addr) { + Object addr_obj; + + addr_obj.push_back(Pair("house_number", addr.house_number_)); + addr_obj.push_back(Pair("road", addr.road_)); + addr_obj.push_back(Pair("town", addr.town_)); + addr_obj.push_back(Pair("county", addr.county_)); + addr_obj.push_back(Pair("country", addr.country_)); + + a.push_back(addr_obj); +} + +Address read_address(const Object& obj) { + Address addr; + + for (Object::size_type i = 0; i != obj.size(); ++i) { + const Pair& pair = obj[i]; + + const string& name = pair.name_; + const Value& value = pair.value_; + + if (name == "house_number") { + addr.house_number_ = value.get_int(); + } else if (name == "road") { + addr.road_ = value.get_str(); + } else if (name == "town") { + addr.town_ = value.get_str(); + } else if (name == "county") { + addr.county_ = value.get_str(); + } else if (name == "country") { + addr.country_ = value.get_str(); + } else { + assert(false); + } + } + + return addr; +} + +void write_addrs(const char* file_name, const Address addrs[]) { + Array addr_array; + + for (int i = 0; i < 5; ++i) { + write_address(addr_array, addrs[i]); + } + + ofstream os(file_name); + + write_formatted(addr_array, os); + + os.close(); +} + +vector
read_addrs(const char* file_name) { + ifstream is(file_name); + + Value value; + + read(is, value); + + const Array& addr_array = value.get_array(); + + vector
addrs; + + for (unsigned int i = 0; i < addr_array.size(); ++i) { + addrs.push_back(read_address(addr_array[i].get_obj())); + } + + return addrs; +} + +int main() { + + const Address addrs[5] = {{42, "East Street", "Newtown", "Essex", "England"}, + {1, "West Street", "Hull", "Yorkshire", "England"}, + {12, "South Road", "Aberystwyth", "Dyfed", "Wales"}, + {45, "North Road", "Paignton", "Devon", "England"}, + {78, "Upper Street", "Ware", "Hertfordshire", "England"}}; + + const char* file_name("demo.txt"); + + write_addrs(file_name, addrs); + + vector
new_addrs = read_addrs(file_name); + + assert(new_addrs.size() == 5); + + for (int i = 0; i < 5; ++i) { + assert(new_addrs[i] == addrs[i]); + } + + std::cout << "json_demo tests all passed" << std::endl; + return 0; +} diff --git a/json_headers_only_demo/json_headers_only_demo.cpp b/json_headers_only_demo/json_headers_only_demo.cpp index 87953ac..4ea4379 100644 --- a/json_headers_only_demo/json_headers_only_demo.cpp +++ b/json_headers_only_demo/json_headers_only_demo.cpp @@ -1,151 +1,132 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -// This demo shows you how to read and write JSON objects and arrays -// using header files only, i.e. not linking to the JSON Spirit object library. -// In this demo objects are stored as a vector of name/value pairs. - -#include "json5_parser_reader_template.h" -#include "json5_parser_writer_template.h" -#include -#include - -#ifndef JSON_SPIRIT_VALUE_ENABLED -#error Please define JSON_SPIRIT_VALUE_ENABLED for the Value type to be enabled -#endif - -using namespace std; -using namespace json5_parser; - -struct Address -{ - int house_number_; - string road_; - string town_; - string county_; - string country_; -}; - -bool operator==( const Address& a1, const Address& a2 ) -{ - return ( a1.house_number_ == a2.house_number_ ) && - ( a1.road_ == a2.road_ ) && - ( a1.town_ == a2.town_ ) && - ( a1.county_ == a2.county_ ) && - ( a1.country_ == a2.country_ ); -} - -void write_address( Array& a, const Address& addr ) -{ - Object addr_obj; - - addr_obj.push_back( Pair( "house_number", addr.house_number_ ) ); - addr_obj.push_back( Pair( "road", addr.road_ ) ); - addr_obj.push_back( Pair( "town", addr.town_ ) ); - addr_obj.push_back( Pair( "county", addr.county_ ) ); - addr_obj.push_back( Pair( "country", addr.country_ ) ); - - a.push_back( addr_obj ); -} - -Address read_address( const Object& obj ) -{ - Address addr; - - for( Object::size_type i = 0; i != obj.size(); ++i ) - { - const Pair& pair = obj[i]; - - const string& name = pair.name_; - const Value& value = pair.value_; - - if( name == "house_number" ) - { - addr.house_number_ = value.get_int(); - } - else if( name == "road" ) - { - addr.road_ = value.get_str(); - } - else if( name == "town" ) - { - addr.town_ = value.get_str(); - } - else if( name == "county" ) - { - addr.county_ = value.get_str(); - } - else if( name == "country" ) - { - addr.country_ = value.get_str(); - } - else - { - assert( false ); - } - } - - return addr; -} - -void write_addrs( const char* file_name, const Address addrs[] ) -{ - Array addr_array; - - for( int i = 0; i < 5; ++i ) - { - write_address( addr_array, addrs[i] ); - } - - ofstream os( file_name ); - - write_stream( Value( addr_array ), os, pretty_print ); // NB need to convert Array to a Value - - os.close(); -} - -vector< Address > read_addrs( const char* file_name ) -{ - ifstream is( file_name ); - - Value value; - - read_stream( is, value ); - - const Array& addr_array = value.get_array(); - - vector< Address > addrs; - - for( unsigned int i = 0; i < addr_array.size(); ++i ) - { - addrs.push_back( read_address( addr_array[i].get_obj() ) ); - } - - return addrs; -} - -int main() -{ - const Address addrs[5] = { { 42, "East Street", "Newtown", "Essex", "England" }, - { 1, "West Street", "Hull", "Yorkshire", "England" }, - { 12, "South Road", "Aberystwyth", "Dyfed", "Wales" }, - { 45, "North Road", "Paignton", "Devon", "England" }, - { 78, "Upper Street", "Ware", "Hertfordshire", "England" } }; - - const char* file_name( "demo.txt" ); - - write_addrs( file_name, addrs ); - - vector< Address > new_addrs = read_addrs( file_name ); - - assert( new_addrs.size() == 5 ); - - for( int i = 0; i < 5; ++i ) - { - assert( new_addrs[i] == addrs[i] ); - } - - return 0; -} +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +// This demo shows you how to read and write JSON objects and arrays +// using header files only, i.e. not linking to the JSON Spirit object library. +// In this demo objects are stored as a vector of name/value pairs. + +#include +#include + +#include "json5_parser_reader_template.h" +#include "json5_parser_writer_template.h" + +#ifndef JSON_SPIRIT_VALUE_ENABLED +#error Please define JSON_SPIRIT_VALUE_ENABLED for the Value type to be enabled +#endif + +using namespace std; +using namespace json5_parser; + +struct Address { + int house_number_; + string road_; + string town_; + string county_; + string country_; +}; + +bool operator==(const Address& a1, const Address& a2) { + return (a1.house_number_ == a2.house_number_) && (a1.road_ == a2.road_) && + (a1.town_ == a2.town_) && (a1.county_ == a2.county_) && + (a1.country_ == a2.country_); +} + +void write_address(Array& a, const Address& addr) { + Object addr_obj; + + addr_obj.push_back(Pair("house_number", addr.house_number_)); + addr_obj.push_back(Pair("road", addr.road_)); + addr_obj.push_back(Pair("town", addr.town_)); + addr_obj.push_back(Pair("county", addr.county_)); + addr_obj.push_back(Pair("country", addr.country_)); + + a.push_back(addr_obj); +} + +Address read_address(const Object& obj) { + Address addr; + + for (Object::size_type i = 0; i != obj.size(); ++i) { + const Pair& pair = obj[i]; + + const string& name = pair.name_; + const Value& value = pair.value_; + + if (name == "house_number") { + addr.house_number_ = value.get_int(); + } else if (name == "road") { + addr.road_ = value.get_str(); + } else if (name == "town") { + addr.town_ = value.get_str(); + } else if (name == "county") { + addr.county_ = value.get_str(); + } else if (name == "country") { + addr.country_ = value.get_str(); + } else { + assert(false); + } + } + + return addr; +} + +void write_addrs(const char* file_name, const Address addrs[]) { + Array addr_array; + + for (int i = 0; i < 5; ++i) { + write_address(addr_array, addrs[i]); + } + + ofstream os(file_name); + + write_stream(Value(addr_array), os, + pretty_print); // NB need to convert Array to a Value + + os.close(); +} + +vector
read_addrs(const char* file_name) { + ifstream is(file_name); + + Value value; + + read_stream(is, value); + + const Array& addr_array = value.get_array(); + + vector
addrs; + + for (unsigned int i = 0; i < addr_array.size(); ++i) { + addrs.push_back(read_address(addr_array[i].get_obj())); + } + + return addrs; +} + +int main() { + const Address addrs[5] = {{42, "East Street", "Newtown", "Essex", "England"}, + {1, "West Street", "Hull", "Yorkshire", "England"}, + {12, "South Road", "Aberystwyth", "Dyfed", "Wales"}, + {45, "North Road", "Paignton", "Devon", "England"}, + {78, "Upper Street", "Ware", "Hertfordshire", "England"}}; + + + // Changed from "demo.txt" because tests were failing. NSF weirdness? + const char* file_name("/tmp/json5_demo.txt"); + + write_addrs(file_name, addrs); + + vector
new_addrs = read_addrs(file_name); + + assert(new_addrs.size() == 5); + + for (int i = 0; i < 5; ++i) { + assert(new_addrs[i] == addrs[i]); + } + + std::cout << "json_headers_only_demo tests all passed" << std::endl; + return 0; +} diff --git a/json_map_demo/json_map_demo.cpp b/json_map_demo/json_map_demo.cpp index 28778e7..3210e02 100644 --- a/json_map_demo/json_map_demo.cpp +++ b/json_map_demo/json_map_demo.cpp @@ -1,133 +1,121 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -// This demo shows you how to read and write JSON objects and arrays. -// In this demo objects are stored as a map of names to values. - -#include "json5_parser.h" -#include -#include - -#ifndef JSON_SPIRIT_MVALUE_ENABLED -#error Please define JSON_SPIRIT_MVALUE_ENABLED for the mValue type to be enabled -#endif - -using namespace std; -using namespace json5_parser; - -struct Address -{ - int house_number_; - string road_; - string town_; - string county_; - string country_; -}; - -bool operator==( const Address& a1, const Address& a2 ) -{ - return ( a1.house_number_ == a2.house_number_ ) && - ( a1.road_ == a2.road_ ) && - ( a1.town_ == a2.town_ ) && - ( a1.county_ == a2.county_ ) && - ( a1.country_ == a2.country_ ); -} - -void write_address( mArray& a, const Address& addr ) -{ - mObject addr_obj; - - addr_obj[ "house_number" ] = addr.house_number_; - addr_obj[ "road" ] = addr.road_; - addr_obj[ "town" ] = addr.town_; - addr_obj[ "county" ] = addr.county_; - addr_obj[ "country" ] = addr.country_; - - a.push_back( addr_obj ); -} - -const mValue& find_value( const mObject& obj, const string& name ) -{ - mObject::const_iterator i = obj.find( name ); - - assert( i != obj.end() ); - assert( i->first == name ); - - return i->second; -} - -Address read_address( const mObject& obj ) -{ - Address addr; - - addr.house_number_ = find_value( obj, "house_number" ).get_int(); - addr.road_ = find_value( obj, "road" ).get_str(); - addr.town_ = find_value( obj, "town" ).get_str(); - addr.county_ = find_value( obj, "county" ).get_str(); - addr.country_ = find_value( obj, "country" ).get_str(); - - return addr; -} - -void write_addrs( const char* file_name, const Address addrs[] ) -{ - mArray addr_array; - - for( int i = 0; i < 5; ++i ) - { - write_address( addr_array, addrs[i] ); - } - - ofstream os( file_name ); - - write_formatted( addr_array, os ); - - os.close(); -} - -vector< Address > read_addrs( const char* file_name ) -{ - ifstream is( file_name ); - - mValue value; - - read( is, value ); - - const mArray& addr_array = value.get_array(); - - vector< Address > addrs; - - for( vector< Address >::size_type i = 0; i < addr_array.size(); ++i ) - { - addrs.push_back( read_address( addr_array[i].get_obj() ) ); - } - - return addrs; -} - -int main() -{ - const Address addrs[5] = { { 42, "East Street", "Newtown", "Essex", "England" }, - { 1, "West Street", "Hull", "Yorkshire", "England" }, - { 12, "South Road", "Aberystwyth", "Dyfed", "Wales" }, - { 45, "North Road", "Paignton", "Devon", "England" }, - { 78, "Upper Street", "Ware", "Hertfordshire", "England" } }; - - const char* file_name( "demo.txt" ); - - write_addrs( file_name, addrs ); - - vector< Address > new_addrs = read_addrs( file_name ); - - assert( new_addrs.size() == 5 ); - - for( int i = 0; i < 5; ++i ) - { - assert( new_addrs[i] == addrs[i] ); - } - - return 0; -} -; \ No newline at end of file +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +// This demo shows you how to read and write JSON objects and arrays. +// In this demo objects are stored as a map of names to values. + +#include +#include + +#include "json5_parser.h" + +#ifndef JSON_SPIRIT_MVALUE_ENABLED +#error Please define JSON_SPIRIT_MVALUE_ENABLED for the mValue type to be enabled +#endif + +using namespace std; +using namespace json5_parser; + +struct Address { + int house_number_; + string road_; + string town_; + string county_; + string country_; +}; + +bool operator==(const Address& a1, const Address& a2) { + return (a1.house_number_ == a2.house_number_) && (a1.road_ == a2.road_) && + (a1.town_ == a2.town_) && (a1.county_ == a2.county_) && + (a1.country_ == a2.country_); +} + +void write_address(mArray& a, const Address& addr) { + mObject addr_obj; + + addr_obj["house_number"] = addr.house_number_; + addr_obj["road"] = addr.road_; + addr_obj["town"] = addr.town_; + addr_obj["county"] = addr.county_; + addr_obj["country"] = addr.country_; + + a.push_back(addr_obj); +} + +const mValue& find_value(const mObject& obj, const string& name) { + mObject::const_iterator i = obj.find(name); + + assert(i != obj.end()); + assert(i->first == name); + + return i->second; +} + +Address read_address(const mObject& obj) { + Address addr; + + addr.house_number_ = find_value(obj, "house_number").get_int(); + addr.road_ = find_value(obj, "road").get_str(); + addr.town_ = find_value(obj, "town").get_str(); + addr.county_ = find_value(obj, "county").get_str(); + addr.country_ = find_value(obj, "country").get_str(); + + return addr; +} + +void write_addrs(const char* file_name, const Address addrs[]) { + mArray addr_array; + + for (int i = 0; i < 5; ++i) { + write_address(addr_array, addrs[i]); + } + + ofstream os(file_name); + + write_formatted(addr_array, os); + + os.close(); +} + +vector
read_addrs(const char* file_name) { + ifstream is(file_name); + + mValue value; + + read(is, value); + + const mArray& addr_array = value.get_array(); + + vector
addrs; + + for (vector
::size_type i = 0; i < addr_array.size(); ++i) { + addrs.push_back(read_address(addr_array[i].get_obj())); + } + + return addrs; +} + +int main() { + const Address addrs[5] = {{42, "East Street", "Newtown", "Essex", "England"}, + {1, "West Street", "Hull", "Yorkshire", "England"}, + {12, "South Road", "Aberystwyth", "Dyfed", "Wales"}, + {45, "North Road", "Paignton", "Devon", "England"}, + {78, "Upper Street", "Ware", "Hertfordshire", "England"}}; + + const char* file_name("map_demo.txt"); + + write_addrs(file_name, addrs); + + vector
new_addrs = read_addrs(file_name); + + assert(new_addrs.size() == 5); + + for (int i = 0; i < 5; ++i) { + assert(new_addrs[i] == addrs[i]); + } + + std::cout << "json_map_demo tests all passed" << std::endl; + return 0; +}; diff --git a/json_test/json5_parser_reader_test.cpp b/json_test/json5_parser_reader_test.cpp index 1137e51..8fbe9f0 100644 --- a/json_test/json5_parser_reader_test.cpp +++ b/json_test/json5_parser_reader_test.cpp @@ -1,925 +1,939 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_reader_test.h" -#include "utils_test.h" -#include "json5_parser_reader.h" -#include "json5_parser_value.h" -#include "json5_parser_writer.h" - -#include -#include -#include -#include -#include - -using namespace json5_parser; -using namespace std; -using namespace boost; -using namespace boost::assign; - -namespace -{ - template< class String_type, class Value_type > - void test_read( const String_type& s, Value_type& value ) - { - // performs both types of read and checks they produce the same value - - read( s, value ); - - Value_type value_2; - - read_or_throw( s, value_2 ); - - assert_eq( value, value_2 ); - } - - template< class Config_type > - struct Test_runner - { - typedef typename Config_type::String_type String_type; - typedef typename Config_type::Object_type Object_type; - typedef typename Config_type::Array_type Array_type; - typedef typename Config_type::Value_type Value_type; - typedef typename Config_type::Pair_type Pair_type; - typedef typename String_type::value_type Char_type; - typedef typename String_type::const_iterator Iter_type; - typedef std::basic_istringstream< Char_type > Istringstream_type; - typedef std::basic_istream< Char_type > Istream_type; - - String_type to_str( const char* c_str ) - { - return ::to_str< String_type >( c_str ); - } - - Test_runner() - { - } - - void check_eq( const Object_type& obj_1, const Object_type& obj_2 ) - { - const typename Object_type::size_type size( obj_1.size() ); - - assert_eq( size, obj_2.size() ); - - typename Object_type::const_iterator i1 = obj_1.begin(); - typename Object_type::const_iterator i2 = obj_2.begin(); - - for( ; i1 != obj_1.end(); ++i1, ++i2 ) - { - assert_eq( *i1, *i2 ); - } - } - - void add_value( Object_type& obj, const char* c_name, const Value_type& value ) - { - Config_type::add( obj, to_str( c_name ), value ); - } - - void add_c_str( Object_type& obj, const char* c_name, const char* c_value ) - { - add_value( obj, c_name, to_str( c_value ) ); - } - - void test_syntax( const char* c_str, bool expected_success = true ) - { - const String_type str = to_str( c_str ); - - Value_type value; - - const bool ok = read( str, value ); - - assert_eq( ok, expected_success ); - - try - { - read_or_throw( str, value ); - - assert( expected_success ); - } - catch( ... ) - { - assert( !expected_success ); - } - } - - template< typename Int > - void test_syntax( Int min_int, Int max_int ) - { - ostringstream os; - - os << "[" << min_int << "," << max_int << "]"; - - test_syntax( os.str().c_str() ); - } - - void test_syntax() - { - test_syntax( "{}" ); - test_syntax( "{ }" ); - test_syntax( "{ } " ); - test_syntax( "{ } " ); - test_syntax( "{\"\":\"\"}" ); - test_syntax( "{\"test\":\"123\"}" ); - test_syntax( "{\"test\" : \"123\"}" ); - test_syntax( "{\"testing testing testing\":\"123\"}" ); - test_syntax( "{\"\":\"abc\"}" ); - test_syntax( "{\"abc\":\"\"}" ); - test_syntax( "{\"\":\"\"}" ); - test_syntax( "{\"test\":true}" ); - test_syntax( "{\"test\":false}" ); - test_syntax( "{\"test\":null}" ); - test_syntax( "{\"test1\":\"123\",\"test2\":\"456\"}" ); - test_syntax( "{\"test1\":\"123\",\"test2\":\"456\",\"test3\":\"789\"}" ); - test_syntax( "{\"test1\":{\"test2\":\"123\",\"test3\":\"456\"}}" ); - test_syntax( "{\"test1\":{\"test2\":{\"test3\":\"456\"}}}" ); - test_syntax( "{\"test1\":[\"a\",\"bb\",\"cc\"]}" ); - test_syntax( "{\"test1\":[true,false,null]}" ); - test_syntax( "{\"test1\":[true,\"abc\",{\"a\":\"b\"},{\"d\":false},null]}" ); - test_syntax( "{\"test1\":[1,2,-3]}" ); - test_syntax( "{\"test1\":[1.1,2e4,-1.234e-34]}" ); - test_syntax( "{\n" - "\t\"test1\":\n" - "\t\t{\n" - "\t\t\t\"test2\":\"123\",\n" - "\t\t\t\"test3\":\"456\"\n" - "\t\t}\n" - "}\n" ); - test_syntax( "[]" ); - test_syntax( "[ ]" ); - test_syntax( "[1,2,3]" ); - test_syntax( "[ 1, -2, 3]" ); - test_syntax( "[ 1.2, -2e6, -3e-6 ]" ); - test_syntax( "[ 1.2, \"str\", -3e-6, { \"field\" : \"data\" } ]" ); - - test_syntax( INT_MIN, INT_MAX ); - test_syntax( LLONG_MIN, LLONG_MAX ); - test_syntax( "[1 2 3]", false ); - test_syntax( "[1,\n2,\n3,]"); - test_syntax( "[0xfreedom]",false); - test_syntax( "[0xreefer]",false); - } - - Value_type read_cstr( const char* c_str ) - { - Value_type value; - - test_read( to_str( c_str ), value ); - - return value; - } - - void read_cstr( const char* c_str, Value_type& value ) - { - test_read( to_str( c_str ), value ); - } - - void check_reading( const char* c_str ) - { - Value_type value; - - String_type in_s( to_str( c_str ) ); - - test_read( in_s, value ); - - const String_type result = write_formatted( value ); - - assert_eq( in_s, result ); - } - - template< typename Int > - void check_reading( Int min_int, Int max_int ) - { - ostringstream os; - - os << "[\n" - " " << min_int << ",\n" - " " << max_int << "\n" - "]"; - - check_reading( os.str().c_str() ); - } - - void test_reading() - { - check_reading( "{\n}" ); - - { - Object_type obj; - Value_type value; - - read_cstr( "{\n" - " name1 : 'value \\\n1',\n" - "}", value ); - - add_c_str( obj, "name1", "value 1" ); - - check_eq( value.get_obj(), obj ); - } - - Object_type obj; - Value_type value; - - read_cstr( "{\n" - " \"name 1\" : \"value 1\"\n" - "}", value ); - - add_c_str( obj, "name 1", "value 1" ); - - check_eq( value.get_obj(), obj ); - - read_cstr( "{\"name 1\":\"value 1\",\"name 2\":\"value 2\"}", value ); - - add_c_str( obj, "name 2", "value 2" ); - - check_eq( value.get_obj(), obj ); - - read_cstr( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : \"value 2\",\n" - " \"name 3\" : \"value 3\"\n" - "}", value ); - - add_c_str( obj, "name 3", "value 3" ); - - check_eq( value.get_obj(), obj ); - - check_reading( "{\n" - " \"\" : \"value\",\n" - " \"name\" : \"\"\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : {\n" - " \"name 3\" : \"value 3\",\n" - " \"name_4\" : \"value_4\"\n" - " }\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : {\n" - " \"name 3\" : \"value 3\",\n" - " \"name_4\" : \"value_4\",\n" - " \"name_5\" : {\n" - " \"name_6\" : \"value_6\",\n" - " \"name_7\" : \"value_7\"\n" - " }\n" - " }\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : {\n" - " \"name 3\" : \"value 3\",\n" - " \"name_4\" : {\n" - " \"name_5\" : \"value_5\",\n" - " \"name_6\" : \"value_6\"\n" - " },\n" - " \"name_7\" : \"value_7\"\n" - " }\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : {\n" - " \"name 3\" : \"value 3\",\n" - " \"name_4\" : {\n" - " \"name_5\" : \"value_5\",\n" - " \"name_6\" : \"value_6\"\n" - " },\n" - " \"name_7\" : \"value_7\"\n" - " },\n" - " \"name_8\" : \"value_8\",\n" - " \"name_9\" : {\n" - " \"name_10\" : \"value_10\"\n" - " }\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : {\n" - " \"name 2\" : {\n" - " \"name 3\" : {\n" - " \"name_4\" : {\n" - " \"name_5\" : \"value\"\n" - " }\n" - " }\n" - " }\n" - " }\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : true,\n" - " \"name 3\" : false,\n" - " \"name_4\" : \"value_4\",\n" - " \"name_5\" : true\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : null,\n" - " \"name 3\" : \"value 3\",\n" - " \"name_4\" : null\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : 123,\n" - " \"name 3\" : \"value 3\",\n" - " \"name_4\" : -567\n" - "}" ); - - check_reading( "[\n]" ); - - check_reading( "[\n" - " 1\n" - "]" ); - - check_reading( "[\n" - " 1,\n" - " 1.2,\n" - " \"john]\",\n" - " true,\n" - " false,\n" - " null\n" - "]" ); - - check_reading( "[\n" - " 1,\n" - " [\n" - " 2,\n" - " 3\n" - " ]\n" - "]" ); - - check_reading( "[\n" - " 1,\n" - " [\n" - " 2,\n" - " 3\n" - " ],\n" - " [\n" - " 4,\n" - " [\n" - " 5,\n" - " 6,\n" - " 7\n" - " ]\n" - " ]\n" - "]" ); - - check_reading( "[\n" - " {\n" - " \"name\" : \"value\"\n" - " }\n" - "]" ); - - check_reading( "{\n" - " \"name\" : [\n" - " 1\n" - " ]\n" - "}" ); - - check_reading( "[\n" - " {\n" - " \"name 1\" : \"value\",\n" - " \"name 2\" : [\n" - " 1,\n" - " 2,\n" - " 3\n" - " ]\n" - " }\n" - "]" ); - - check_reading( "{\n" - " \"name 1\" : [\n" - " 1,\n" - " {\n" - " \"name 2\" : \"value 2\"\n" - " }\n" - " ]\n" - "}" ); - - check_reading( "[\n" - " {\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : [\n" - " 1,\n" - " 2,\n" - " {\n" - " \"name 3\" : \"value 3\"\n" - " }\n" - " ]\n" - " }\n" - "]" ); - - check_reading( "{\n" - " \"name 1\" : [\n" - " 1,\n" - " {\n" - " \"name 2\" : [\n" - " 1,\n" - " 2,\n" - " 3\n" - " ]\n" - " }\n" - " ]\n" - "}" ); - - check_reading( INT_MIN, INT_MAX ); - check_reading( LLONG_MIN, LLONG_MAX ); - } - - void test_reading_reals() - { - Value_type value; - - const String_type in_s = to_str( "[1.200000000000000,1.234567890123456e+125,-1.234000000000000e-123," - " 1.000000000000000e-123,1234567890.123456,123,]" ); - - basic_istringstream< Char_type > is( in_s ); - - const bool ok = read( is, value ); - - assert_eq( ok, true ); - assert_eq( value.type(), array_type ); - - const Array_type arr = value.get_array(); - - assert_eq( arr.size(), 6u ); - assert_eq( arr[0].get_real(), 1.2, 1e-16 ); - assert_eq( arr[1].get_real(), 1.234567890123456e+125, 1e+110 ); - assert_eq( arr[2].get_real(), -1.234e-123, 1e+108 ); - assert_eq( arr[3].get_real(), 1e-123, 1e+108 ); - assert_eq( arr[4].get_real(), 1234567890.123456, 1e-7 ); - assert_eq( arr[5].get_real(), 123, 1e-13 ); - } - - void test_from_stream( const char* json_str, bool expected_success, - const Error_position& expected_error ) - { - Value_type value; - - String_type in_s( to_str( json_str ) ); - - basic_istringstream< Char_type > is( in_s ); - - const bool ok = read( is, value ); - - assert_eq( ok, expected_success ); - - if( ok ) - { - assert_eq( in_s, write( value ) ); - } - - try - { - basic_istringstream< Char_type > is( in_s ); - - read_or_throw( is, value ); - - assert_eq( expected_success, true ); - - assert_eq( in_s, write( value ) ); - } - catch( const Error_position error ) - { - assert_eq( error, expected_error ); - } - } - - void test_from_stream() - { - test_from_stream( "[1,2]", true, Error_position() ); - test_from_stream( "\n\n foo", false, Error_position( 3, 2,"not a value" ) ); - } - - void test_escape_chars( const char* json_str, const char* c_str ) - { - Value_type value; - - string s( string( "{\"" ) + json_str + "\" : \"" + json_str + "\"} " ); - - read_cstr( s.c_str(), value ); - - const Pair_type& pair( *value.get_obj().begin() ); - - assert_eq( Config_type::get_name ( pair ), to_str( c_str ) ); - assert_eq( Config_type::get_value( pair ), to_str( c_str ) ); - } - - void test_escape_chars() - { - test_escape_chars( "\\t", "\t"); - test_escape_chars( "a\\t", "a\t" ); - test_escape_chars( "\\tb", "\tb" ); - test_escape_chars( "a\\tb", "a\tb" ); - test_escape_chars( "a\\tb", "a\tb" ); - test_escape_chars( "a123\\tb", "a123\tb" ); - test_escape_chars( "\\t\\n\\\\", "\t\n\\" ); - test_escape_chars( "\\/\\r\\b\\f\\\"", "/\r\b\f\"" ); - test_escape_chars( "\\h\\j\\k", "" ); // invalid esc chars - test_escape_chars( "\\x61\\x62\\x63", "abc" ); - test_escape_chars( "a\\x62c", "abc" ); - test_escape_chars( "\\x01\\x02\\x7F", "\x01\x02\x7F" ); // NB x7F is the greatest char spirit will parse - test_escape_chars( "\\u0061\\u0062\\u0063", "abc" ); - } - - void check_is_null( const char* c_str ) - { - assert_eq( read_cstr( c_str ).type(), null_type ); - } - - template< typename T > - void check_value( const char* c_str, const T& expected_value ) - { - const Value_type v( read_cstr( c_str ) ); - - assert_eq( v.template get_value< T >(), expected_value ); - } - - void test_values() - { - check_value( "1", 1 ); - check_value( "+Infinity", std::numeric_limits::infinity() ); - check_value( "Infinity", std::numeric_limits::infinity() ); - check_value( "-Infinity", -std::numeric_limits::infinity() ); - check_value( "0xfe", 0xfe ); - check_value( "1.5", 1.5 ); - check_value( "\"Test\"", to_str( "Test" ) ); - check_value( "true", true ); - check_value( "false", false ); - check_is_null( "null" ); - } - - void check_read_fails( const char* c_str, int line, int column, const string& reason ) - { - Value_type value; - - try - { - read_cstr( c_str, value ); - - assert( false ); - } - catch( const Error_position posn ) - { - assert_eq( posn, Error_position( line, column, reason ) ); - } - } - - void test_error_cases() - { - check_read_fails( "", 1, 1, "not a value" ); - check_read_fails( "foo", 1, 1, "not a value" ); - check_read_fails( " foo", 1, 2, "not a value" ); - check_read_fails( " foo", 1, 3, "not a value" ); - check_read_fails( "\n\n foo", 3, 2, "not a value" ); - check_read_fails( "!!!", 1, 1, "not a value" ); - check_read_fails( "\"bar", 1, 1, "not a value" ); - check_read_fails( "0xreefer", 1, 3, "not a hexadecimal number" ); - check_read_fails( "bar\"", 1, 1, "not a value" ); - check_read_fails( "[1}", 1, 3, "not an array" ); - check_read_fails( "[1,2?", 1, 5, "not an array" ); - check_read_fails( "[1,2}", 1, 5, "not an array" ); - check_read_fails( "[1;2]", 1, 3, "not an array" ); - check_read_fails( "{\"name\":\"value\"]", 1, 16, "not an object" ); - check_read_fails( "{\"name\",\"value\"}", 1, 8, "no colon in pair" ); - check_read_fails( "{\n1:\"value\"}", 2, 1, "not an object" ); - check_read_fails( "{\n name\":\"value\"}", 2, 7, "no colon in pair" ); - check_read_fails( "{\"name\":foo}", 1, 9, "not a value" ); - check_read_fails( "{\"name\":0xfreedom}", 1, 12, "not an object" ); - check_read_fails( "{\"name\":value\"}", 1, 9, "not a value" ); - check_read_fails( "{'name':\"value\"}", 1, 2, "not an object" ); - } - - typedef vector< int > Ints; - - bool test_read_range( Iter_type& first, Iter_type last, Value_type& value ) - { - Iter_type first_ = first; - - const bool ok = read( first, last, value ); - - try - { - Value_type value_; - - read_or_throw( first_, last, value_ ); - - assert_eq( ok, true ); - assert_eq( value, value_ ); - } - catch( ... ) - { - assert_eq( ok, false ); - } - - return ok; - } - - void check_value_sequence( Iter_type first, Iter_type last, const Ints& expected_values, bool all_input_consumed ) - { - Value_type value; - - for( Ints::size_type i = 0; i < expected_values.size(); ++i ) - { - const bool ok = test_read_range( first, last, value ); - - assert_eq( ok, true ); - - const bool is_last( i == expected_values.size() - 1 ); - - assert_eq( first == last, is_last ? all_input_consumed : false ); - } - - const bool ok = test_read_range( first, last, value ); - - assert_eq( ok, false ); - } - - void check_value_sequence( Istream_type& is, const Ints& expected_values, bool all_input_consumed ) - { - Value_type value; - - for( Ints::size_type i = 0; i < expected_values.size(); ++i ) - { - read_or_throw( is, value ); - - assert_eq( value.get_int(), expected_values[i] ); - - const bool is_last( i == expected_values.size() - 1 ); - - assert_eq( is.eof(), is_last ? all_input_consumed : false ); - } - - try - { - read_or_throw( is, value ); - - assert( false ); - } - catch( ... ) - { - } - - assert_eq( is.eof(), true ); - } - - void check_value_sequence( const char* c_str, const Ints& expected_values, bool all_input_consumed ) - { - const String_type s( to_str( c_str ) ); - - check_value_sequence( s.begin(), s.end(), expected_values, all_input_consumed ); - - Istringstream_type is( s ); - - check_value_sequence( is, expected_values, all_input_consumed ); - } - - void check_array( const Value_type& value, typename Array_type::size_type expected_size ) - { - assert_eq( value.type(), array_type ); - - const Array_type& arr = value.get_array(); - - assert_eq( arr.size(), expected_size ); - - for( typename Array_type::size_type i = 0; i < expected_size; ++i ) - { - const Value_type& val = arr[i]; - - assert_eq( val.type(), int_type ); - assert_eq( val.get_int(), int( i + 1 ) ); - } - } - - void check_reading_array( Iter_type& begin, Iter_type end, typename Array_type::size_type expected_size ) - { - Value_type value; - - test_read_range( begin, end, value ); - - check_array( value, expected_size ); - } - - void check_reading_array( Istream_type& is, typename Array_type::size_type expected_size ) - { - Value_type value; - - read( is, value ); - - check_array( value, expected_size ); - } - - void check_reading_arrays( const char* arrays_str ) - { - const String_type str( to_str( arrays_str ) ); - - Iter_type begin = str.begin(); - const Iter_type end = str.end(); - - check_reading_array( begin, end, 0 ); - check_reading_array( begin, end, 1 ); - check_reading_array( begin, end, 2 ); - check_reading_array( begin, end, 3 ); - - Istringstream_type is( str ); - - check_reading_array( is, 0 ); - check_reading_array( is, 1 ); - check_reading_array( is, 2 ); - check_reading_array( is, 3 ); - } - - void test_sequence_of_values() - { - check_value_sequence( "", Ints(), false ); - check_value_sequence( " ", Ints(), false ); - check_value_sequence( " ", Ints(), false ); - check_value_sequence( " 10 ", list_of( 10 ), false ); - check_value_sequence( " 10 11 ", list_of( 10 )( 11 ), false ); - check_value_sequence( " 10 11 12", list_of( 10 )( 11 )( 12 ), true); - check_value_sequence( "10 11 12", list_of( 10 )( 11 )( 12 ), true); - - // - - check_reading_arrays( "[] [ 1 ] [ 1, 2 ] [ 1, 2, 3 ]" ); - // check_reading_arrays( "[][1][1,2][1,2,3]" ); // fails due to multi_pass iterator bug, - // use stream_reader class instead - } - - void test_uint64( const char* value_str, int expected_int, int64_t expected_int64, uint64_t expected_uint64 ) - { - const Value_type v( read_cstr( value_str ) ); - - assert_eq( v.get_int(), expected_int ); - assert_eq( v.get_int64(), expected_int64 ); - assert_eq( v.get_uint64(), expected_uint64 ); - } - - void test_uint64() - { - test_uint64( "0", 0, 0, 0 ); - test_uint64( "1", 1, 1, 1 ); - test_uint64( "-1", -1, -1, ULLONG_MAX ); - test_uint64( "18446744073709551615", -1, -1, ULLONG_MAX ); - } - - void test_types() - { - Value_type value; - - read( to_str( "[ \"foo\", true, false, 1, 12.3, null ]" ), value ); - - assert_eq( value.type(), array_type ); - - const Array_type& a = value.get_array(); - - assert_eq( a[0].get_str(), to_str( "foo" ) ); - assert_eq( a[1].get_bool(), true ); - assert_eq( a[2].get_bool(), false ); - assert_eq( a[3].get_int(), 1 ); - assert_eq( a[3].get_int64(), 1 ); - assert_eq( a[3].get_uint64(), 1u ); - assert_eq( a[3].get_real(), 1.0 ); - assert_eq( a[4].get_real(), 12.3 ); - assert_eq( a[5].is_null(), true ); - } - - void test_comments() - { - Value_type value_1; - - read_cstr( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : \"value 2 /* not a comment but data */\",\n" - " \"name 3\" : \"value 3 // not a comment but data\"\n" - "}", value_1 ); - - Value_type value_2; - - read_cstr( "{// a comment\n " - " \"name 1\" : /* another comment */ \"value 1\",\n" - " \"name 2\" : \"value 2 /* not a comment but data */\",\n" - " // \"name 2\" : \"value 2\",\n" - " \"name 3\" : \"value 3 // not a comment but data\"\n" - "/* multi\n" - "line\n" - "comment */}", value_2 ); - - assert_eq( value_1, value_2 ); - } - - void run_tests() - { - test_syntax(); - test_reading(); - test_reading_reals(); - test_from_stream(); - test_escape_chars(); - test_values(); - test_error_cases(); - test_sequence_of_values(); - test_uint64(); - test_types(); - test_comments(); - } - }; - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void test_wide_esc_u() - { - wValue value; - - test_read( L"[\"\\uABCD\"]", value ); - - const wstring s( value.get_array()[0].get_str() ); - - assert_eq( s.length(), static_cast< wstring::size_type >( 1u ) ); - assert_eq( s[0], 0xABCD ); - } -#endif - -#ifdef JSON_SPIRIT_VALUE_ENABLED - void test_extended_ascii( const string& s ) - { - Value value; - - test_read( "[\"" + s + "\"]", value ); - - assert_eq( value.get_array()[0].get_str(), "äöüß" ); - } - - void test_extended_ascii() - { - test_extended_ascii( "\\u00E4\\u00F6\\u00FC\\u00DF" ); - test_extended_ascii( "äöüß" ); - } -#endif -} - -//#include - -void json5_parser::test_reader() -{ -#ifdef JSON_SPIRIT_VALUE_ENABLED - Test_runner< Config >().run_tests(); - test_extended_ascii(); -#endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED - Test_runner< mConfig >().run_tests(); -#endif -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Test_runner< wConfig >().run_tests(); - test_wide_esc_u(); -#endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Test_runner< wmConfig >().run_tests(); -#endif - -#ifndef _DEBUG - //ifstream ifs( "test.txt" ); - - //string s; - - //getline( ifs, s ); - - //timer t; - - //for( int i = 0; i < 2000; ++i ) - //{ - // Value value; - - // read( s, value ); - //} - - //cout << t.elapsed() << endl; - -// const string so = write( value ); - - //Object obj; - - //for( int i = 0; i < 100000; ++i ) - //{ - // obj.push_back( Pair( "\x01test\x7F", lexical_cast< string >( i ) ) ); - //} - - //const string s = write( obj ); - - //Value value; - - //timer t; - - //read( s, value ); - - //cout << t.elapsed() << endl; - - //cout << "obj size " << value.get_obj().size(); -#endif -} +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_reader_test.h" +#include "json5_parser_reader.h" +#include "json5_parser_value.h" +#include "json5_parser_writer.h" +#include "utils_test.h" + +#include +#include +#include +#include +#include + +using namespace json5_parser; +using namespace std; +using namespace boost; +using namespace boost::assign; + +namespace { +template +void test_read(const String_type& s, Value_type& value) { + // performs both types of read and checks they produce the same value + + read(s, value); + + Value_type value_2; + + read_or_throw(s, value_2); + + assert_eq(value, value_2); +} + +template +struct Test_runner { + typedef typename Config_type::String_type String_type; + typedef typename Config_type::Object_type Object_type; + typedef typename Config_type::Array_type Array_type; + typedef typename Config_type::Value_type Value_type; + typedef typename Config_type::Pair_type Pair_type; + typedef typename String_type::value_type Char_type; + typedef typename String_type::const_iterator Iter_type; + typedef std::basic_istringstream Istringstream_type; + typedef std::basic_istream Istream_type; + + String_type to_str(const char* c_str) { return ::to_str(c_str); } + + Test_runner() {} + + void check_eq(const Object_type& obj_1, const Object_type& obj_2) { + const typename Object_type::size_type size(obj_1.size()); + + assert_eq(size, obj_2.size()); + + typename Object_type::const_iterator i1 = obj_1.begin(); + typename Object_type::const_iterator i2 = obj_2.begin(); + + for (; i1 != obj_1.end(); ++i1, ++i2) { + assert_eq(*i1, *i2); + } + } + + void add_value(Object_type& obj, const char* c_name, const Value_type& value) { + Config_type::add(obj, to_str(c_name), value); + } + + void add_c_str(Object_type& obj, const char* c_name, const char* c_value) { + add_value(obj, c_name, to_str(c_value)); + } + + void test_syntax(const char* c_str, bool expected_success = true) { + const String_type str = to_str(c_str); + + Value_type value; + + const bool ok = read(str, value); + + assert_eq(ok, expected_success); + + try { + read_or_throw(str, value); + + assert(expected_success); + } catch (...) { + assert(!expected_success); + } + } + + template + void test_syntax(Int min_int, Int max_int) { + ostringstream os; + + os << "[" << min_int << "," << max_int << "]"; + + test_syntax(os.str().c_str()); + } + + void test_syntax() { + test_syntax("{}"); + test_syntax("{ }"); + test_syntax("{ } "); + test_syntax("{ } "); + test_syntax("{\"\":\"\"}"); + test_syntax("{\"test\":\"123\"}"); + test_syntax("{\"test\" : \"123\"}"); + test_syntax("{\"testing testing testing\":\"123\"}"); + test_syntax("{\"\":\"abc\"}"); + test_syntax("{\"abc\":\"\"}"); + test_syntax("{\"\":\"\"}"); + test_syntax("{\"test\":true}"); + test_syntax("{\"test\":false}"); + test_syntax("{\"test\":null}"); + test_syntax("{\"test1\":\"123\",\"test2\":\"456\"}"); + test_syntax("{\"test1\":\"123\",\"test2\":\"456\",\"test3\":\"789\"}"); + test_syntax("{\"test1\":{\"test2\":\"123\",\"test3\":\"456\"}}"); + test_syntax("{\"test1\":{\"test2\":{\"test3\":\"456\"}}}"); + test_syntax("{\"test1\":[\"a\",\"bb\",\"cc\"]}"); + test_syntax("{\"test1\":[true,false,null]}"); + test_syntax("{\"test1\":[true,\"abc\",{\"a\":\"b\"},{\"d\":false},null]}"); + test_syntax("{\"test1\":[1,2,-3]}"); + test_syntax("{\"test1\":[1.1,2e4,-1.234e-34]}"); + test_syntax( + "{\n" + "\t\"test1\":\n" + "\t\t{\n" + "\t\t\t\"test2\":\"123\",\n" + "\t\t\t\"test3\":\"456\"\n" + "\t\t}\n" + "}\n"); + test_syntax("[]"); + test_syntax("[ ]"); + test_syntax("[1,2,3]"); + test_syntax("[ 1, -2, 3]"); + test_syntax("[ 1.2, -2e6, -3e-6 ]"); + test_syntax("[ 1.2, \"str\", -3e-6, { \"field\" : \"data\" } ]"); + + test_syntax(INT_MIN, INT_MAX); + test_syntax(LLONG_MIN, LLONG_MAX); + test_syntax("[1 2 3]", false); + test_syntax("[1,\n2,\n3,]"); + test_syntax("[0xfreedom]", false); + test_syntax("[0xreefer]", false); + } + + Value_type read_cstr(const char* c_str) { + Value_type value; + + test_read(to_str(c_str), value); + + return value; + } + + void read_cstr(const char* c_str, Value_type& value) { + test_read(to_str(c_str), value); + } + + void check_reading(const char* c_str) { + Value_type value; + + String_type in_s(to_str(c_str)); + + test_read(in_s, value); + + const String_type result = write_formatted(value); + + assert_eq(in_s, result); + } + + template + void check_reading(Int min_int, Int max_int) { + ostringstream os; + + os << "[\n" + " " + << min_int + << ",\n" + " " + << max_int + << "\n" + "]"; + + check_reading(os.str().c_str()); + } + + void test_reading() { + check_reading("{\n}"); + + { + Object_type obj; + Value_type value; + + read_cstr( + "{\n" + " name1 : 'value \\\n1',\n" + "}", + value); + + add_c_str(obj, "name1", "value 1"); + + check_eq(value.get_obj(), obj); + } + + { + Object_type obj; + Value_type value; + + read_cstr( + "{\n" + " \"name 1\" : \"value 1\"\n" + "}", + value); + + add_c_str(obj, "name 1", "value 1"); + + check_eq(value.get_obj(), obj); + + read_cstr("{\"name 1\":\"value 1\",\"name 2\":\"value 2\"}", value); + + add_c_str(obj, "name 2", "value 2"); + + check_eq(value.get_obj(), obj); + + read_cstr( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : \"value 2\",\n" + " \"name 3\" : \"value 3\"\n" + "}", + value); + + add_c_str(obj, "name 3", "value 3"); + + check_eq(value.get_obj(), obj); + } + + { + Object_type obj; + Value_type value; + + read_cstr( + "{\n" + " name 1 : \"value 1\"\n" + "}", + value); + + add_c_str(obj, "name 1", "value 1"); + check_eq(value.get_obj(), obj); + } + + check_reading( + "{\n" + " \"\" : \"value\",\n" + " \"name\" : \"\"\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : {\n" + " \"name 3\" : \"value 3\",\n" + " \"name_4\" : \"value_4\"\n" + " }\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : {\n" + " \"name 3\" : \"value 3\",\n" + " \"name_4\" : \"value_4\",\n" + " \"name_5\" : {\n" + " \"name_6\" : \"value_6\",\n" + " \"name_7\" : \"value_7\"\n" + " }\n" + " }\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : {\n" + " \"name 3\" : \"value 3\",\n" + " \"name_4\" : {\n" + " \"name_5\" : \"value_5\",\n" + " \"name_6\" : \"value_6\"\n" + " },\n" + " \"name_7\" : \"value_7\"\n" + " }\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : {\n" + " \"name 3\" : \"value 3\",\n" + " \"name_4\" : {\n" + " \"name_5\" : \"value_5\",\n" + " \"name_6\" : \"value_6\"\n" + " },\n" + " \"name_7\" : \"value_7\"\n" + " },\n" + " \"name_8\" : \"value_8\",\n" + " \"name_9\" : {\n" + " \"name_10\" : \"value_10\"\n" + " }\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : {\n" + " \"name 2\" : {\n" + " \"name 3\" : {\n" + " \"name_4\" : {\n" + " \"name_5\" : \"value\"\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : true,\n" + " \"name 3\" : false,\n" + " \"name_4\" : \"value_4\",\n" + " \"name_5\" : true\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : null,\n" + " \"name 3\" : \"value 3\",\n" + " \"name_4\" : null\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : 123,\n" + " \"name 3\" : \"value 3\",\n" + " \"name_4\" : -567\n" + "}"); + + check_reading("[\n]"); + + check_reading( + "[\n" + " 1\n" + "]"); + + check_reading( + "[\n" + " 1,\n" + " 1.2,\n" + " \"john]\",\n" + " true,\n" + " false,\n" + " null\n" + "]"); + + check_reading( + "[\n" + " 1,\n" + " [\n" + " 2,\n" + " 3\n" + " ]\n" + "]"); + + check_reading( + "[\n" + " 1,\n" + " [\n" + " 2,\n" + " 3\n" + " ],\n" + " [\n" + " 4,\n" + " [\n" + " 5,\n" + " 6,\n" + " 7\n" + " ]\n" + " ]\n" + "]"); + + check_reading( + "[\n" + " {\n" + " \"name\" : \"value\"\n" + " }\n" + "]"); + + check_reading( + "{\n" + " \"name\" : [\n" + " 1\n" + " ]\n" + "}"); + + check_reading( + "[\n" + " {\n" + " \"name 1\" : \"value\",\n" + " \"name 2\" : [\n" + " 1,\n" + " 2,\n" + " 3\n" + " ]\n" + " }\n" + "]"); + + check_reading( + "{\n" + " \"name 1\" : [\n" + " 1,\n" + " {\n" + " \"name 2\" : \"value 2\"\n" + " }\n" + " ]\n" + "}"); + + check_reading( + "[\n" + " {\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : [\n" + " 1,\n" + " 2,\n" + " {\n" + " \"name 3\" : \"value 3\"\n" + " }\n" + " ]\n" + " }\n" + "]"); + + check_reading( + "{\n" + " \"name 1\" : [\n" + " 1,\n" + " {\n" + " \"name 2\" : [\n" + " 1,\n" + " 2,\n" + " 3\n" + " ]\n" + " }\n" + " ]\n" + "}"); + + check_reading(INT_MIN, INT_MAX); + check_reading(LLONG_MIN, LLONG_MAX); + } + + void test_reading_reals() { + Value_type value; + + const String_type in_s = to_str( + "[1.200000000000000,1.234567890123456e+125,-1.234000000000000e-123," + " 1.000000000000000e-123,1234567890.123456,123,]"); + + basic_istringstream is(in_s); + + const bool ok = read(is, value); + + assert_eq(ok, true); + assert_eq(value.type(), array_type); + + const Array_type arr = value.get_array(); + + assert_eq(arr.size(), 6u); + assert_eq(arr[0].get_real(), 1.2, 1e-16); + assert_eq(arr[1].get_real(), 1.234567890123456e+125, 1e+110); + assert_eq(arr[2].get_real(), -1.234e-123, 1e+108); + assert_eq(arr[3].get_real(), 1e-123, 1e+108); + assert_eq(arr[4].get_real(), 1234567890.123456, 1e-7); + assert_eq(arr[5].get_real(), 123, 1e-13); + } + + void test_from_stream(const char* json_str, bool expected_success, + const Error_position& expected_error) { + Value_type value; + + String_type in_s(to_str(json_str)); + + basic_istringstream is(in_s); + + const bool ok = read(is, value); + + assert_eq(ok, expected_success); + + if (ok) { + assert_eq(in_s, write(value)); + } + + try { + basic_istringstream is(in_s); + + read_or_throw(is, value); + + assert_eq(expected_success, true); + + assert_eq(in_s, write(value)); + } catch (const Error_position error) { + assert_eq(error, expected_error); + } + } + + void test_from_stream() { + test_from_stream("[1,2]", true, Error_position()); + test_from_stream("\n\n foo", false, Error_position(3, 2, "not a value")); + } + + void test_escape_chars(const char* json_str, const char* c_str) { + Value_type value; + + string s(string("{\"") + json_str + "\" : \"" + json_str + "\"} "); + + read_cstr(s.c_str(), value); + + const Pair_type& pair(*value.get_obj().begin()); + + assert_eq(Config_type::get_name(pair), to_str(c_str)); + assert_eq(Config_type::get_value(pair), to_str(c_str)); + } + + void test_escape_chars() { + test_escape_chars("\\t", "\t"); + test_escape_chars("a\\t", "a\t"); + test_escape_chars("\\tb", "\tb"); + test_escape_chars("a\\tb", "a\tb"); + test_escape_chars("a\\tb", "a\tb"); + test_escape_chars("a123\\tb", "a123\tb"); + test_escape_chars("\\t\\n\\\\", "\t\n\\"); + test_escape_chars("\\/\\r\\b\\f\\\"", "/\r\b\f\""); + test_escape_chars("\\h\\j\\k", ""); // invalid esc chars + test_escape_chars("\\x61\\x62\\x63", "abc"); + test_escape_chars("a\\x62c", "abc"); + test_escape_chars( + "\\x01\\x02\\x7F", + "\x01\x02\x7F"); // NB x7F is the greatest char spirit will parse + test_escape_chars("\\u0061\\u0062\\u0063", "abc"); + } + + void check_is_null(const char* c_str) { + assert_eq(read_cstr(c_str).type(), null_type); + } + + template + void check_value(const char* c_str, const T& expected_value) { + const Value_type v(read_cstr(c_str)); + + assert_eq(v.template get_value(), expected_value); + } + + void test_values() { + check_value("1", 1); + check_value("+Infinity", std::numeric_limits::infinity()); + check_value("Infinity", std::numeric_limits::infinity()); + check_value("-Infinity", -std::numeric_limits::infinity()); + check_value("0xfe", 0xfe); + check_value("1.5", 1.5); + check_value("\"Test\"", to_str("Test")); + check_value("true", true); + check_value("false", false); + check_is_null("null"); + } + + void check_read_fails(const char* c_str, int line, int column, + const string& reason) { + Value_type value; + + try { + read_cstr(c_str, value); + + assert(false); + } catch (const Error_position posn) { + assert_eq(posn, Error_position(line, column, reason)); + } + } + + void test_error_cases() { + check_read_fails("", 1, 1, "not a value"); + check_read_fails("foo", 1, 1, "not a value"); + check_read_fails(" foo", 1, 2, "not a value"); + check_read_fails(" foo", 1, 3, "not a value"); + check_read_fails("\n\n foo", 3, 2, "not a value"); + check_read_fails("!!!", 1, 1, "not a value"); + check_read_fails("\"bar", 1, 1, "not a value"); + check_read_fails("0xreefer", 1, 3, "not a hexadecimal number"); + check_read_fails("bar\"", 1, 1, "not a value"); + check_read_fails("[1}", 1, 3, "not an array"); + check_read_fails("[1,2?", 1, 5, "not an array"); + check_read_fails("[1,2}", 1, 5, "not an array"); + check_read_fails("[1;2]", 1, 3, "not an array"); + check_read_fails("{\"name\":\"value\"]", 1, 16, "not an object"); + check_read_fails("{\"name\",\"value\"}", 1, 8, "no colon in pair"); + check_read_fails("{\n1:\"value\"}", 2, 1, "not an object"); + check_read_fails("{\n name\":\"value\"}", 2, 7, "no colon in pair"); + check_read_fails("{\"name\":foo}", 1, 9, "not a value"); + check_read_fails("{\"name\":0xfreedom}", 1, 12, "not an object"); + check_read_fails("{\"name\":value\"}", 1, 9, "not a value"); + check_read_fails("{'name':\"value\"}", 1, 2, "not an object"); + } + + typedef vector Ints; + + bool test_read_range(Iter_type& first, Iter_type last, Value_type& value) { + Iter_type first_ = first; + + const bool ok = read(first, last, value); + + try { + Value_type value_; + + read_or_throw(first_, last, value_); + + assert_eq(ok, true); + assert_eq(value, value_); + } catch (...) { + assert_eq(ok, false); + } + + return ok; + } + + void check_value_sequence(Iter_type first, Iter_type last, + const Ints& expected_values, bool all_input_consumed) { + Value_type value; + + for (Ints::size_type i = 0; i < expected_values.size(); ++i) { + const bool ok = test_read_range(first, last, value); + + assert_eq(ok, true); + + const bool is_last(i == expected_values.size() - 1); + + assert_eq(first == last, is_last ? all_input_consumed : false); + } + + const bool ok = test_read_range(first, last, value); + + assert_eq(ok, false); + } + + void check_value_sequence(Istream_type& is, const Ints& expected_values, + bool all_input_consumed) { + Value_type value; + + for (Ints::size_type i = 0; i < expected_values.size(); ++i) { + read_or_throw(is, value); + + assert_eq(value.get_int(), expected_values[i]); + + const bool is_last(i == expected_values.size() - 1); + + assert_eq(is.eof(), is_last ? all_input_consumed : false); + } + + try { + read_or_throw(is, value); + + assert(false); + } catch (...) { + } + + assert_eq(is.eof(), true); + } + + void check_value_sequence(const char* c_str, const Ints& expected_values, + bool all_input_consumed) { + const String_type s(to_str(c_str)); + + check_value_sequence(s.begin(), s.end(), expected_values, all_input_consumed); + + Istringstream_type is(s); + + check_value_sequence(is, expected_values, all_input_consumed); + } + + void check_array(const Value_type& value, + typename Array_type::size_type expected_size) { + assert_eq(value.type(), array_type); + + const Array_type& arr = value.get_array(); + + assert_eq(arr.size(), expected_size); + + for (typename Array_type::size_type i = 0; i < expected_size; ++i) { + const Value_type& val = arr[i]; + + assert_eq(val.type(), int_type); + assert_eq(val.get_int(), int(i + 1)); + } + } + + void check_reading_array(Iter_type& begin, Iter_type end, + typename Array_type::size_type expected_size) { + Value_type value; + + test_read_range(begin, end, value); + + check_array(value, expected_size); + } + + void check_reading_array(Istream_type& is, + typename Array_type::size_type expected_size) { + Value_type value; + + read(is, value); + + check_array(value, expected_size); + } + + void check_reading_arrays(const char* arrays_str) { + const String_type str(to_str(arrays_str)); + + Iter_type begin = str.begin(); + const Iter_type end = str.end(); + + check_reading_array(begin, end, 0); + check_reading_array(begin, end, 1); + check_reading_array(begin, end, 2); + check_reading_array(begin, end, 3); + + Istringstream_type is(str); + + check_reading_array(is, 0); + is.unget(); + check_reading_array(is, 1); + is.unget(); + check_reading_array(is, 2); + is.unget(); + check_reading_array(is, 3); + } + + void test_sequence_of_values() { + check_value_sequence("", Ints(), false); + check_value_sequence(" ", Ints(), false); + check_value_sequence(" ", Ints(), false); + check_value_sequence(" 10 ", list_of(10), false); + check_value_sequence(" 10 11 ", list_of(10)(11), false); + check_value_sequence(" 10 11 12", list_of(10)(11)(12), true); + check_value_sequence("10 11 12", list_of(10)(11)(12), true); + + // Note: check_reading_arrays() expects exactly this list of arrays. + check_reading_arrays("[] [ 1 ] [ 1, 2 ] [ 1, 2, 3 ]"); + check_reading_arrays("[][1][1,2][1,2,3]"); + } + + void test_uint64(const char* value_str, int expected_int, int64_t expected_int64, + uint64_t expected_uint64) { + const Value_type v(read_cstr(value_str)); + + assert_eq(v.get_int(), expected_int); + assert_eq(v.get_int64(), expected_int64); + assert_eq(v.get_uint64(), expected_uint64); + } + + void test_uint64() { + test_uint64("0", 0, 0, 0); + test_uint64("1", 1, 1, 1); + test_uint64("-1", -1, -1, ULLONG_MAX); + test_uint64("18446744073709551615", -1, -1, ULLONG_MAX); + } + + void test_types() { + Value_type value; + + read(to_str("[ \"foo\", true, false, 1, 12.3, null ]"), value); + + assert_eq(value.type(), array_type); + + const Array_type& a = value.get_array(); + + assert_eq(a[0].get_str(), to_str("foo")); + assert_eq(a[1].get_bool(), true); + assert_eq(a[2].get_bool(), false); + assert_eq(a[3].get_int(), 1); + assert_eq(a[3].get_int64(), 1); + assert_eq(a[3].get_uint64(), 1u); + assert_eq(a[3].get_real(), 1.0); + assert_eq(a[4].get_real(), 12.3); + assert_eq(a[5].is_null(), true); + } + + void test_comments() { + Value_type value_1; + + read_cstr( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : \"value 2 /* not a comment but data */\",\n" + " \"name 3\" : \"value 3 // not a comment but data\"\n" + "}", + value_1); + + Value_type value_2; + + read_cstr( + "{// a comment\n " + " \"name 1\" : /* another comment */ \"value 1\",\n" + " \"name 2\" : \"value 2 /* not a comment but data */\",\n" + " // \"name 2\" : \"value 2\",\n" + " \"name 3\" : \"value 3 // not a comment but data\"\n" + "/* multi\n" + "line\n" + "comment */}", + value_2); + + assert_eq(value_1, value_2); + } + + void run_tests() { + std::cout << " before test_syntax()" << std::endl; + test_syntax(); + std::cout << " before test_reading()" << std::endl; + test_reading(); + std::cout << " before test_reading_reals()" << std::endl; + test_reading_reals(); + std::cout << " before test_from_stream()" << std::endl; + test_from_stream(); + std::cout << " before test_escape_chars()" << std::endl; + test_escape_chars(); + std::cout << " before test_values()" << std::endl; + test_values(); + std::cout << " before test_error_cases()" << std::endl; + test_error_cases(); + std::cout << " before test_sequence_of_values()" << std::endl; + test_sequence_of_values(); + std::cout << " before test_uint64()" << std::endl; + test_uint64(); + std::cout << " before test_types()" << std::endl; + test_types(); + std::cout << " before test_comments()" << std::endl; + test_comments(); + } +}; + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void test_wide_esc_u() { + wValue value; + + test_read(L"[\"\\uABCD\"]", value); + + const wstring s(value.get_array()[0].get_str()); + + assert_eq(s.length(), static_cast(1u)); + assert_eq(s[0], 0xABCD); +} +#endif + +#ifdef JSON_SPIRIT_VALUE_ENABLED +void test_extended_ascii(const string& s) { + Value value; + + test_read("[\"" + s + "\"]", value); + + assert_eq(value.get_array()[0].get_str(), "äöüß"); +} + +void test_extended_ascii() { + test_extended_ascii("\\u00E4\\u00F6\\u00FC\\u00DF"); + test_extended_ascii("äöüß"); +} +#endif +} // namespace + +//#include + +void json5_parser::test_reader() { +#ifdef JSON_SPIRIT_VALUE_ENABLED + std::cout << " JSON_SPIRIT_VALUE_ENABLED" << std::endl; + Test_runner().run_tests(); + test_extended_ascii(); +#endif +#ifdef JSON_SPIRIT_MVALUE_ENABLED + std::cout << " JSON_SPIRIT_MVALUE_ENABLED" << std::endl; + Test_runner().run_tests(); +#endif +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + std::cout << " defined(JSON_SPIRIT_WVALUE_ENABLED) && " + "!defined(BOOST_NO_STD_WSTRING)" + << std::endl; + Test_runner().run_tests(); + test_wide_esc_u(); +#endif +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + std::cout << " defined(JSON_SPIRIT_WMVALUE_ENABLED) && " + "!defined(BOOST_NO_STD_WSTRING)" + << std::endl; + Test_runner().run_tests(); +#endif + +#ifndef _DEBUG + // ifstream ifs( "test.txt" ); + + // string s; + + // getline( ifs, s ); + + // timer t; + + // for( int i = 0; i < 2000; ++i ) + //{ + // Value value; + + // read( s, value ); + //} + + // cout << t.elapsed() << endl; + + // const string so = write( value ); + + // Object obj; + + // for( int i = 0; i < 100000; ++i ) + //{ + // obj.push_back( Pair( "\x01test\x7F", lexical_cast< string >( i ) ) ); + //} + + // const string s = write( obj ); + + // Value value; + + // timer t; + + // read( s, value ); + + // cout << t.elapsed() << endl; + + // cout << "obj size " << value.get_obj().size(); +#endif +} diff --git a/json_test/json5_parser_reader_test.h b/json_test/json5_parser_reader_test.h index 02542f9..2896798 100644 --- a/json_test/json5_parser_reader_test.h +++ b/json_test/json5_parser_reader_test.h @@ -1,18 +1,17 @@ -#ifndef JSON_SPIRIT_READER_TEST -#define JSON_SPIRIT_READER_TEST - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -namespace json5_parser -{ - void test_reader(); -} - -#endif +#ifndef JSON_SPIRIT_READER_TEST +#define JSON_SPIRIT_READER_TEST + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +namespace json5_parser { +void test_reader(); +} + +#endif diff --git a/json_test/json5_parser_stream_reader_test.cpp b/json_test/json5_parser_stream_reader_test.cpp index 359b9d0..9638980 100644 --- a/json_test/json5_parser_stream_reader_test.cpp +++ b/json_test/json5_parser_stream_reader_test.cpp @@ -1,137 +1,120 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_stream_reader_test.h" -#include "utils_test.h" -#include "json5_parser_stream_reader.h" - -#include -#include - -using namespace json5_parser; -using namespace std; -using namespace boost; -using namespace boost::assign; - -namespace -{ - template< class Config_type > - struct Test_runner - { - typedef typename Config_type::String_type String_type; - typedef typename Config_type::Object_type Object_type; - typedef typename Config_type::Array_type Array_type; - typedef typename Config_type::Value_type Value_type; - typedef typename Config_type::Pair_type Pair_type; - typedef typename String_type::value_type Char_type; - typedef typename String_type::const_iterator Iter_type; - typedef std::basic_istringstream< Char_type > Istringstream_type; - typedef std::basic_istream< Char_type > Istream_type; - - String_type to_str( const char* c_str ) - { - return ::to_str< String_type >( c_str ); - } - - Test_runner() - { - } - - void check_stream_reader( Stream_reader< Istream_type, Value_type >& reader, const vector< int >& expected_result ) - { - Value_type v; - const bool ok = reader.read_next( v ); - assert_eq( ok, true ); - assert_eq( v.type(), array_type ); - assert_eq( v.get_array().size(), expected_result.size() ); - for( vector< int >::size_type i = 0; i < v.get_array().size(); ++i ) - { - assert_eq( v.get_array()[i], expected_result[i] ); - } - } - - void check_stream_read_or_throw( Stream_reader_thrower< Istream_type, Value_type >& reader, const vector< int >& expected_result ) - { - Value_type v; - - try - { - reader.read_next( v ); - assert_eq( v.type(), array_type ); - assert_eq( v.get_array().size(), expected_result.size() ); - for( vector< int >::size_type i = 0; i < v.get_array().size(); ++i ) - { - assert_eq( v.get_array()[i], expected_result[i] ); - } - } - catch( ... ) - { - assert( false ); - } - } - - void test_stream_reader( const char* s ) - { - { - Istringstream_type is( to_str( s ) ); - - Stream_reader< Istream_type, Value_type > reader( is ); - - check_stream_reader( reader, vector< int >() ); - check_stream_reader( reader, list_of( 1 ) ); - check_stream_reader( reader, list_of( 1 )( 2 ) ); - check_stream_reader( reader, list_of( 1 )( 2 )( 3 ) ); - - Value_type v; - const bool ok = reader.read_next( v ); - assert_eq( ok, false ); - } - { - Istringstream_type is( to_str( s ) ); - - Stream_reader_thrower< Istream_type, Value_type > reader( is ); - - check_stream_read_or_throw( reader, vector< int >() ); - check_stream_read_or_throw( reader, list_of( 1 ) ); - check_stream_read_or_throw( reader, list_of( 1 )( 2 ) ); - check_stream_read_or_throw( reader, list_of( 1 )( 2 )( 3 ) ); - - try - { - Value_type v; - reader.read_next( v ); - assert( false ); - } - catch( ... ) - { - } - } - } - - void run_tests() - { - test_stream_reader( "[][1][1,2][1,2,3]" ); - test_stream_reader( "[] [1] [1,2] [1,2,3]" ); - test_stream_reader( " [] [1] [1,2] [1,2,3] " ); - } - }; -} - -void json5_parser::test_stream_reader() -{ -#ifdef JSON_SPIRIT_VALUE_ENABLED - Test_runner< Config >().run_tests(); -#endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED - Test_runner< mConfig >().run_tests(); -#endif - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Test_runner< wConfig >().run_tests(); -#endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Test_runner< wmConfig >().run_tests(); -#endif -} +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_stream_reader_test.h" +#include "json5_parser_stream_reader.h" +#include "utils_test.h" + +#include +#include + +using namespace json5_parser; +using namespace std; +using namespace boost; +using namespace boost::assign; + +namespace { +template +struct Test_runner { + typedef typename Config_type::String_type String_type; + typedef typename Config_type::Object_type Object_type; + typedef typename Config_type::Array_type Array_type; + typedef typename Config_type::Value_type Value_type; + typedef typename Config_type::Pair_type Pair_type; + typedef typename String_type::value_type Char_type; + typedef typename String_type::const_iterator Iter_type; + typedef std::basic_istringstream Istringstream_type; + typedef std::basic_istream Istream_type; + + String_type to_str(const char* c_str) { return ::to_str(c_str); } + + Test_runner() {} + + void check_stream_reader(Stream_reader& reader, + const vector& expected_result) { + Value_type v; + const bool ok = reader.read_next(v); + assert_eq(ok, true); + assert_eq(v.type(), array_type); + assert_eq(v.get_array().size(), expected_result.size()); + for (vector::size_type i = 0; i < v.get_array().size(); ++i) { + assert_eq(v.get_array()[i], expected_result[i]); + } + } + + void check_stream_read_or_throw( + Stream_reader_thrower& reader, + const vector& expected_result) { + Value_type v; + + try { + reader.read_next(v); + assert_eq(v.type(), array_type); + assert_eq(v.get_array().size(), expected_result.size()); + for (vector::size_type i = 0; i < v.get_array().size(); ++i) { + assert_eq(v.get_array()[i], expected_result[i]); + } + } catch (...) { + assert(false); + } + } + + void test_stream_reader(const char* s) { + { + Istringstream_type is(to_str(s)); + + Stream_reader reader(is); + + check_stream_reader(reader, vector()); + check_stream_reader(reader, list_of(1)); + check_stream_reader(reader, list_of(1)(2)); + check_stream_reader(reader, list_of(1)(2)(3)); + + Value_type v; + const bool ok = reader.read_next(v); + assert_eq(ok, false); + } + { + Istringstream_type is(to_str(s)); + + Stream_reader_thrower reader(is); + + check_stream_read_or_throw(reader, vector()); + check_stream_read_or_throw(reader, list_of(1)); + check_stream_read_or_throw(reader, list_of(1)(2)); + check_stream_read_or_throw(reader, list_of(1)(2)(3)); + + try { + Value_type v; + reader.read_next(v); + assert(false); + } catch (...) { + } + } + } + + void run_tests() { + test_stream_reader("[][1][1,2][1,2,3]"); + test_stream_reader("[] [1] [1,2] [1,2,3]"); + test_stream_reader(" [] [1] [1,2] [1,2,3] "); + } +}; +} // namespace + +void json5_parser::test_stream_reader() { +#ifdef JSON_SPIRIT_VALUE_ENABLED + Test_runner().run_tests(); +#endif +#ifdef JSON_SPIRIT_MVALUE_ENABLED + Test_runner().run_tests(); +#endif + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Test_runner().run_tests(); +#endif +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Test_runner().run_tests(); +#endif +} diff --git a/json_test/json5_parser_stream_reader_test.h b/json_test/json5_parser_stream_reader_test.h index 1b9f102..495db4c 100644 --- a/json_test/json5_parser_stream_reader_test.h +++ b/json_test/json5_parser_stream_reader_test.h @@ -1,18 +1,17 @@ -#ifndef JSON_SPIRIT_STREAM_READER_TEST -#define JSON_SPIRIT_STREAM_READER_TEST - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -namespace json5_parser -{ - void test_stream_reader(); -} - -#endif +#ifndef JSON_SPIRIT_STREAM_READER_TEST +#define JSON_SPIRIT_STREAM_READER_TEST + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +namespace json5_parser { +void test_stream_reader(); +} + +#endif diff --git a/json_test/json5_parser_utils_test.cpp b/json_test/json5_parser_utils_test.cpp index e5ee9c3..bf62b4b 100644 --- a/json_test/json5_parser_utils_test.cpp +++ b/json_test/json5_parser_utils_test.cpp @@ -1,143 +1,131 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_utils_test.h" -#include "utils_test.h" -#include "json5_parser_utils.h" - -#include - -using namespace json5_parser; -using namespace std; -using namespace boost::assign; - -namespace -{ - template< class Obj_t, class Map_t > - struct Test_runner - { - typedef typename Map_t::key_type String_type; - typedef typename Obj_t::value_type Pair_type; - typedef typename Pair_type::Value_type Value_type; - - String_type to_str( const char* c_str ) - { - return ::to_str< String_type >( c_str ); - } - - void assert_equal( const Obj_t& obj, const Map_t& mp_obj ) - { - typename Obj_t::size_type obj_size = obj.size(); - typename Map_t::size_type map_size = mp_obj.size(); - - assert_eq( obj_size, map_size ); - - for( typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i ) - { - assert_eq( mp_obj.find( i->name_ )->second, i->value_ ); - } - } - - void check_obj_to_map( const Obj_t& obj ) - { - Map_t mp_obj; - - obj_to_map( obj, mp_obj ); - - assert_equal( obj, mp_obj ); - } - - void check_map_cleared() - { - Map_t mp_obj; - - mp_obj[ to_str( "del" ) ] = to_str( "me" ); - - obj_to_map( Obj_t(), mp_obj ); - - assert_eq( mp_obj.size(), 0u ); - } - - void check_map_to_obj( const Map_t& mp_obj ) - { - Obj_t obj; - - map_to_obj( mp_obj, obj ); - - assert_equal( obj, mp_obj ); - } - - void check_obj_cleared() - { - Obj_t obj; - - obj.push_back( Pair_type( to_str( "del" ), to_str( "me" ) ) ); - - map_to_obj( Map_t(), obj ); - - assert_eq( obj.size(), 0u ); - } - - void test_obj_to_map() - { - check_obj_to_map( Obj_t() ); - check_obj_to_map( list_of( Pair_type( to_str( "a" ), 1 ) ) ); - check_obj_to_map( list_of( Pair_type( to_str( "a" ), 1 ) )( Pair_type( to_str( "b" ), 2 ) ) ); - check_obj_to_map( list_of( Pair_type( to_str( "a" ), 1 ) )( Pair_type( to_str( "b" ), 2 ) )( Pair_type( to_str( "c" ), 3 ) ) ); - check_map_cleared(); - - check_map_to_obj( Map_t() ); - check_map_to_obj( map_list_of( to_str( "a" ), 1 ) ); - check_map_to_obj( map_list_of( to_str( "a" ), 1 )( to_str( "b" ), 2 ) ); - check_map_to_obj( map_list_of( to_str( "a" ), 1 )( to_str( "b" ), 2 )( to_str( "c" ), 3 ) ); - check_obj_cleared(); - } - - void check_find( const Obj_t& obj, const char* name, const Value_type& expected_result ) - { - const Value_type& result = find_value( obj, to_str( name ) ); - - assert_eq( result, expected_result ); - } - - void test_find() - { - check_find( Obj_t(), "not there", Value_type::null ); - - const Obj_t obj_1 = list_of( Pair_type( to_str( "a" ), 1 ) ); - - check_find( obj_1, "not there", Value_type::null ); - check_find( obj_1, "a", 1 ); - - const Obj_t obj_2 = list_of( Pair_type( to_str( "a" ), 1 ) )( Pair_type( to_str( "ab" ), 2 ) ); - - check_find( obj_2, "a", 1 ); - check_find( obj_2, "ab", 2 ); - - const Obj_t obj_3 = list_of( Pair_type( to_str( "a" ), 1 ) )( Pair_type( to_str( "ab" ), 2 ) )( Pair_type( to_str( "abc" ), 3 ) ); - - check_find( obj_3, "a", 1 ); - check_find( obj_3, "ab", 2 ); - check_find( obj_3, "abc", 3 ); - } - - void run_tests() - { - test_obj_to_map(); - test_find(); - } - }; -} - -void json5_parser::test_utils() -{ -#ifdef JSON_SPIRIT_VALUE_ENABLED - Test_runner< Object, Mapped_obj >().run_tests(); -#endif - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Test_runner< wObject, wMapped_obj >().run_tests(); -#endif -} +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_utils_test.h" +#include "json5_parser_utils.h" +#include "utils_test.h" + +#include + +using namespace json5_parser; +using namespace std; +using namespace boost::assign; + +namespace { +template +struct Test_runner { + typedef typename Map_t::key_type String_type; + typedef typename Obj_t::value_type Pair_type; + typedef typename Pair_type::Value_type Value_type; + + String_type to_str(const char* c_str) { return ::to_str(c_str); } + + void assert_equal(const Obj_t& obj, const Map_t& mp_obj) { + typename Obj_t::size_type obj_size = obj.size(); + typename Map_t::size_type map_size = mp_obj.size(); + + assert_eq(obj_size, map_size); + + for (typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i) { + assert_eq(mp_obj.find(i->name_)->second, i->value_); + } + } + + void check_obj_to_map(const Obj_t& obj) { + Map_t mp_obj; + + obj_to_map(obj, mp_obj); + + assert_equal(obj, mp_obj); + } + + void check_map_cleared() { + Map_t mp_obj; + + mp_obj[to_str("del")] = to_str("me"); + + obj_to_map(Obj_t(), mp_obj); + + assert_eq(mp_obj.size(), 0u); + } + + void check_map_to_obj(const Map_t& mp_obj) { + Obj_t obj; + + map_to_obj(mp_obj, obj); + + assert_equal(obj, mp_obj); + } + + void check_obj_cleared() { + Obj_t obj; + + obj.push_back(Pair_type(to_str("del"), to_str("me"))); + + map_to_obj(Map_t(), obj); + + assert_eq(obj.size(), 0u); + } + + void test_obj_to_map() { + check_obj_to_map(Obj_t()); + check_obj_to_map(list_of(Pair_type(to_str("a"), 1))); + check_obj_to_map(list_of(Pair_type(to_str("a"), 1))(Pair_type(to_str("b"), 2))); + check_obj_to_map(list_of(Pair_type(to_str("a"), 1))(Pair_type(to_str("b"), 2))( + Pair_type(to_str("c"), 3))); + check_map_cleared(); + + check_map_to_obj(Map_t()); + check_map_to_obj(map_list_of(to_str("a"), 1)); + check_map_to_obj(map_list_of(to_str("a"), 1)(to_str("b"), 2)); + check_map_to_obj(map_list_of(to_str("a"), 1)(to_str("b"), 2)(to_str("c"), 3)); + check_obj_cleared(); + } + + void check_find(const Obj_t& obj, const char* name, + const Value_type& expected_result) { + const Value_type& result = find_value(obj, to_str(name)); + + assert_eq(result, expected_result); + } + + void test_find() { + check_find(Obj_t(), "not there", Value_type::null); + + const Obj_t obj_1 = list_of(Pair_type(to_str("a"), 1)); + + check_find(obj_1, "not there", Value_type::null); + check_find(obj_1, "a", 1); + + const Obj_t obj_2 = + list_of(Pair_type(to_str("a"), 1))(Pair_type(to_str("ab"), 2)); + + check_find(obj_2, "a", 1); + check_find(obj_2, "ab", 2); + + const Obj_t obj_3 = list_of(Pair_type(to_str("a"), 1))( + Pair_type(to_str("ab"), 2))(Pair_type(to_str("abc"), 3)); + + check_find(obj_3, "a", 1); + check_find(obj_3, "ab", 2); + check_find(obj_3, "abc", 3); + } + + void run_tests() { + test_obj_to_map(); + test_find(); + } +}; +} // namespace + +void json5_parser::test_utils() { +#ifdef JSON_SPIRIT_VALUE_ENABLED + Test_runner().run_tests(); +#endif + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Test_runner().run_tests(); +#endif +} diff --git a/json_test/json5_parser_utils_test.h b/json_test/json5_parser_utils_test.h index 7c80523..fb07418 100644 --- a/json_test/json5_parser_utils_test.h +++ b/json_test/json5_parser_utils_test.h @@ -1,18 +1,17 @@ -#ifndef JSON_SPIRIT_UTILS_TEST -#define JSON_SPIRIT_UTILS_TEST - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -namespace json5_parser -{ - void test_utils(); -} - -#endif +#ifndef JSON_SPIRIT_UTILS_TEST +#define JSON_SPIRIT_UTILS_TEST + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +namespace json5_parser { +void test_utils(); +} + +#endif diff --git a/json_test/json5_parser_value_test.cpp b/json_test/json5_parser_value_test.cpp index 63eec79..5c650a4 100644 --- a/json_test/json5_parser_value_test.cpp +++ b/json_test/json5_parser_value_test.cpp @@ -1,529 +1,533 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_value_test.h" -#include "utils_test.h" -#include "json5_parser_value.h" -#include -#include -#include -#include - -using namespace json5_parser; -using namespace std; -using namespace boost; -using namespace boost::assign; - -namespace -{ -#ifdef JSON_SPIRIT_VALUE_ENABLED - - const int64_t max_int64 = integer_traits< int64_t >::max(); - const uint64_t max_uint64 = integer_traits< uint64_t >::max(); - - void test_obj_value() - { - const Pair p1( "name1", "value1" ); - const Pair p3( "name3", "value3" ); - - Object obj_1; obj_1.push_back( p1 ); - Object obj_2; obj_2.push_back( p1 ); - Object obj_3; obj_3.push_back( p3 ); - - Value v1( obj_1 ); - Value v2( obj_2 ); - Value v3( obj_3 ); - - assert_eq( v1.type(), obj_type ); - assert_eq ( v1, v2 ); - assert_neq( v1, v3 ); - - assert_eq( v1.get_obj(), obj_1 ); - assert_eq( v3.get_obj(), obj_3 ); - } - - void test_array_value() - { - Array array_1; array_1.push_back( 1 ); array_1.push_back( "2" ); - Array array_2; array_2.push_back( 1 ); array_2.push_back( "2" ); - Array array_3; array_3.push_back( 1 ); array_3.push_back( "X" ); - - Value v1( array_1 ); - Value v2( array_2 ); - Value v3( array_3 ); - - assert_eq( v1.type(), array_type ); - assert_eq ( v1, v2 ); - assert_neq( v1, v3 ); - - assert_eq( v1.get_array(), array_1 ); - assert_eq( v3.get_array(), array_3 ); - } - - void test_bool_value() - { - Value v1( true ); - Value v2( true ); - Value v3( false ); - - assert_eq( v1.type(), bool_type ); - assert_eq ( v1, v2 ); - assert_neq( v1, v3 ); - - assert( v1.get_bool() ); - assert( !v3.get_bool() ); - } - - void test_int_value() - { - Value v1( 1 ); - Value v2( 1 ); - Value v3( INT_MAX ); - - assert_eq( v1.type(), int_type ); - assert_eq ( v1, v2 ); - assert_neq( v1, v3 ); - - unsigned int uint_max = INT_MAX; - - assert_eq( v1.get_int(), 1 ); - assert_eq( v1.get_int64(), 1 ); - assert_eq( v1.get_uint64(), 1u ); - assert_eq( v3.get_int(), INT_MAX ); - assert_eq( v3.get_int64(), INT_MAX ); - assert_eq( v3.get_uint64(), uint_max ); - - Value v4( max_int64 ); - - assert_eq( v4.get_int64(), max_int64 ); - assert_eq( v4.get_uint64(), static_cast< uint64_t >( max_int64 ) ); - - const uint64_t max_int64_plus_1 = max_int64 + uint64_t( 1 ); - - Value v5( max_int64_plus_1 ); - - assert_eq( v5.get_uint64(), max_int64_plus_1 ); - - Value v6( max_uint64 ); - - assert_eq( v6.get_uint64(), max_uint64 ); - - Value v7( 0 ); - - assert_eq( v7.get_int(), 0 ); - assert_eq( v7.get_int64(), 0 ); - assert_eq( v7.get_uint64(), 0u ); - - Value v8( -1 ); - - assert_eq( v8.get_int(), -1 ); - assert_eq( v8.get_int64(), -1 ); - assert_eq( v8.get_uint64(), max_uint64 ); - } - - void test_real_value() - { - Value v1( 1.0 ); - Value v2( 1.0 ); - Value v3( 2.0 ); - - assert_eq( v1.type(), real_type ); - assert_eq ( v1, v2 ); - assert_neq( v1, v3 ); - - assert_eq( v1.get_real(), 1.0 ); - assert_eq( v3.get_real(), 2.0 ); - } - - void test_null_value() - { - Value v1; - Value v2; - - assert_eq( v1.type(), null_type ); - assert_eq( v1.is_null(), true ); - assert_eq( v1, v2 ); - assert_eq( v1.is_null(), true ); - assert_eq( Value( 1 ).is_null(), false ); - } - - template< typename T > - void test_get_value( const T& t ) - { - assert_eq( Value( t ).get_value< T >(), t ); - } - - void test_get_value() - { - test_get_value( 123 ); - test_get_value( max_int64 ); - test_get_value( 1.23 ); - test_get_value( true ); - test_get_value( false ); - test_get_value( string( "test" ) ); - - Array a; a.push_back( 1 ); a.push_back( "2" ); - - test_get_value( a ); - - Object obj; obj.push_back( Pair( "name1", "value1" ) ); - - test_get_value( obj ); - } - - void assert_array_eq( const Value& v, const Array& a ) - { - assert_eq( v.get_array(), a ); - } - - void assert_obj_eq( const Value& v, const Object& obj ) - { - assert_eq( v.get_obj(), obj ); - } - - template< typename T > - void check_copy( const T& t ) - { - const Value v1( t ); - const Value v2( v1 ); - Value v3; - v3 = v1; - - assert_eq( v1, v2 ); - assert_eq( v1, v3 ); - - assert_eq( v2.get_value< T >(), t ); - assert_eq( v3.get_value< T >(), t ); - - assert_eq( v1.is_uint64(), v2.is_uint64() ); - assert_eq( v1.is_uint64(), v3.is_uint64() ); - } - - void check_copying_null() - { - const Value v1; - const Value v2( v1 ); - Value v3; - v3 = v1; - - assert_eq( v2.type(), null_type ); - assert_eq( v3.type(), null_type ); - } - - void test_copying() - { - { - const Array array_1 = list_of(1)(2); - - Value v1( array_1 ); - const Value v2( v1 ); - - assert_array_eq( v1, array_1 ); - assert_array_eq( v2, array_1 ); - - v1.get_array()[0] = 3; - - assert_array_eq( v1, list_of(3)(2) ); - assert_array_eq( v2, array_1 ); - } - { - const Object obj_1 = list_of( Pair( "a", 1 ) )( Pair( "b", 2 ) ); - - Value v1( obj_1 ); - Value v2; - - v2 = v1; - - assert_obj_eq( v1, obj_1 ); - assert_obj_eq( v2, obj_1 ); - - v1.get_obj()[0] = Pair( "c", 3 ); - - assert_obj_eq( v1, list_of( Pair( "c", 3 ) )( Pair( "b", 2 ) ) ); - assert_obj_eq( v2, obj_1 ); - } - { - check_copy( 1 ); - check_copy( 2.0 ); - check_copy( max_int64 ); - check_copy( max_uint64 ); - check_copy( string("test") ); - check_copy( true ); - check_copy( false ); - const Array array_1 = list_of(1)(2); - check_copy( array_1 ); - const Object obj_1 = list_of( Pair( "a", 1 ) )( Pair( "b", 2 ) ); - check_copy( obj_1 ); - check_copying_null(); - } - } - - void test_obj_map_implemention() - { -#ifdef JSON_SPIRIT_MVALUE_ENABLED - mObject obj; - - obj[ "name 1" ] = 1; - obj[ "name 2" ] = "two"; - - assert_eq( obj.size(), 2u ); - - assert_eq( obj.find( "name 1" )->second.get_int(), 1 ); - assert_eq( obj.find( "name 2" )->second.get_str(), "two" ); -#endif - } - - template< typename Int > - void check_an_int_is_a_real( Int i, bool expected_result ) - { - assert_eq( Value( i ).is_uint64(), expected_result ); - } - - void test_is_uint64() - { - check_an_int_is_a_real( 1, false ); - check_an_int_is_a_real( static_cast< int64_t >( 1 ), false ); - check_an_int_is_a_real( static_cast< uint64_t >( 1 ), true ); - } - - template< typename Int > - void check_an_int_is_a_real( Int i, double expected_result ) - { - assert_eq( Value( i ).get_real(), expected_result ); - } - - void test_an_int_is_a_real() - { - check_an_int_is_a_real( -1, -1.0 ); - check_an_int_is_a_real( 0, 0.0 ); - check_an_int_is_a_real( 1, 1.0 ); - check_an_int_is_a_real( max_int64, 9223372036854775800.0 ); - check_an_int_is_a_real( max_uint64, 18446744073709552000.0 ); - } - - template< typename T > - void check_wrong_type_exceptions( const Value& v, const string& requested_type_name, const string& actual_type_name ) - { - try - { - v.get_value< T >(); - - assert( false ); - } - catch( const runtime_error& e ) - { - ostringstream os; - - os << "get_value< " << requested_type_name << " > called on " << actual_type_name << " Value"; - - assert_eq( e.what(), os.str() ); - } - } - - template< typename T > - void check_wrong_type_exceptions( const string& requested_type_name ) - { - Value v; - - assert_eq( v.type(), null_type ); - - check_wrong_type_exceptions< T >( v, requested_type_name, "null" ); - } - - void test_wrong_type_exceptions() - { - check_wrong_type_exceptions< Object >( "Object" ); - check_wrong_type_exceptions< Array >( "Array" ); - check_wrong_type_exceptions< string >( "string" ); - check_wrong_type_exceptions< bool >( "boolean"); - check_wrong_type_exceptions< boost::int64_t >( "integer" ); - check_wrong_type_exceptions< int >( "integer" ); - check_wrong_type_exceptions< double >( "real" ); - - Value v( "string" ); - - assert_eq( v.type(), str_type ); - - check_wrong_type_exceptions< double >( v, "real", "string" ); - } -#endif - - template< class Config_type > - class Container_constructor_runner - { - public: - - Container_constructor_runner() - { - vector< double > vd = list_of( 1.2 )( 1.3 ); test_container_constructor( vd ); - vector< int > vi = list_of( 1 ); test_container_constructor( vi ); - vi = list_of( 1 )( 2 ); test_container_constructor( vi ); - vi = list_of( 1 )( 2 )( 3 ); test_container_constructor( vi ); - list< double > ld = list_of( 1.2 )( 1.3 ); test_container_constructor( ld ); - list< int > li = list_of( 1 ); test_container_constructor( li ); - li = list_of( 1 )( 2 ); test_container_constructor( li ); - li = list_of( 1 )( 2 )( 3 ); test_container_constructor( li ); - } - - private: - - typedef typename Config_type::Array_type Array_type; - typedef typename Config_type::Value_type Value_type; - - template< class Cont > - void test_container_constructor( const Cont& cont ) - { - typedef typename Cont::value_type Cont_value_type; - const Value_type val( cont.begin(), cont.end() ); - const Array_type& arr = val.get_array(); - Cont result; - for( unsigned int i = 0; i < arr.size(); ++i ) - { - result.push_back( arr[i].template get_value< Cont_value_type>() ); - } - assert_eq( result, cont ); - } - }; - - void test_container_constructor() - { -#ifdef JSON_SPIRIT_VALUE_ENABLED - Container_constructor_runner< Config >(); -#endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED - Container_constructor_runner< mConfig >(); -#endif -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Container_constructor_runner< wConfig >(); -#endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Container_constructor_runner< wmConfig >(); -#endif - } - - template< class Config_type > - class Variant_constructor_runner - { - public: - - Variant_constructor_runner() - { - test_variant_constructor< variant< int, double > >( 1.23 ); - test_variant_constructor< variant< int, double > >( 123 ); - test_variant_constructor< variant< int, double, String_type > >( to_str< String_type >( "foo" ) ); - test_variant_constructor< variant< int, double, String_type, bool > >( true ); - test_variant_constructor< variant< int, double, String_type, bool, boost::int64_t > >( boost::int64_t( 123 ) ); - test_variant_constructor< variant< int, double, String_type, bool, boost::uint64_t > >( boost::uint64_t( 123 ) ); - - { - variant< int, Null > variant = Null(); - const Value_type val( variant ); - assert( val.is_null() ); - } - - vector< double > vd = list_of( 1.2 )( 1.3 ); test_variant_array_constructor< double > ( vd ); - vector< int > vi = list_of( 1 ); test_variant_array_constructor< int >( vi ); - vi = list_of( 1 )( 2 ); test_variant_array_constructor< int >( vi ); - vi = list_of( 1 )( 2 )( 3 ); test_variant_array_constructor< int >( vi ); - list< double > ld = list_of( 1.2 )( 1.3 ); test_variant_array_constructor< double >( ld ); - list< int > li = list_of( 1 ); test_variant_array_constructor< int >( li ); - li = list_of( 1 )( 2 ); test_variant_array_constructor< int >( li ); - li = list_of( 1 )( 2 )( 3 ); test_variant_array_constructor< int >( li ); - } - - private: - - typedef typename Config_type::String_type String_type; - typedef typename Config_type::Array_type Array_type; - typedef typename Config_type::Value_type Value_type; - - template< class Variant_t, typename T > - void test_variant_constructor( const T& t ) - { - const Variant_t variant( t ); - const Value_type val( variant ); - assert_eq( val.template get_value< T >(), t ); - } - - template< typename T, typename A, template< typename, typename > class Cont > - void test_variant_array_constructor( const Cont< T, A >& cont ) - { - const variant< int, Cont< T, A > > variant = cont; - const Value_type val( variant ); - const Array_type& arr = val.get_array(); - Cont< T, A > result; - for( unsigned int i = 0; i < arr.size(); ++i ) - { - result.push_back( arr[i].template get_value< T >() ); - } - assert_eq( result, cont ); - } - }; - - void test_variant_constructor() - { -#ifdef JSON_SPIRIT_VALUE_ENABLED - Variant_constructor_runner< Config >(); -#endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED - Variant_constructor_runner< mConfig >(); - -#endif -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Variant_constructor_runner< wConfig >(); -#endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Variant_constructor_runner< wmConfig >(); -#endif - } -} - -void json5_parser::test_value() -{ -#ifdef JSON_SPIRIT_VALUE_ENABLED - Object obj; - Value value_str ( "value" ); - Value value_obj ( obj ); - Value value_bool( true ); - - Value value_str_2 ( string( "value" ) ); - Value value_obj_2 ( obj ); - Value value_bool_2( false ); - - const char* str( "value" ); - Value value_str_2b ( str ); - - assert_eq( value_str, value_str ); - assert_eq( value_str, value_str_2 ); - assert_eq( value_str, value_str_2b ); - assert_eq( value_obj, value_obj ); - assert_eq( value_obj, value_obj_2 ); - assert_neq( value_str, value_obj ); - assert_neq( value_str, value_bool ); - - Object obj_2; - obj_2.push_back( Pair( "name", value_str ) ); - Value value_str_3( "xxxxx" ); - Value value_obj_3( obj_2 ); - - assert_neq( value_str, value_str_3 ); - assert_neq( value_obj, value_obj_3 ); - - test_obj_value(); - test_array_value(); - test_bool_value(); - test_int_value(); - test_real_value(); - test_null_value(); - test_get_value(); - test_copying(); - test_obj_map_implemention(); - test_is_uint64(); - test_an_int_is_a_real(); - test_wrong_type_exceptions(); -#endif - test_container_constructor(); - test_variant_constructor(); -} +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_value_test.h" +#include +#include +#include +#include +#include "json5_parser_value.h" +#include "utils_test.h" + +using namespace json5_parser; +using namespace std; +using namespace boost; +using namespace boost::assign; + +namespace { +#ifdef JSON_SPIRIT_VALUE_ENABLED + +const int64_t max_int64 = integer_traits::max(); +const uint64_t max_uint64 = integer_traits::max(); + +void test_obj_value() { + const Pair p1("name1", "value1"); + const Pair p3("name3", "value3"); + + Object obj_1; + obj_1.push_back(p1); + Object obj_2; + obj_2.push_back(p1); + Object obj_3; + obj_3.push_back(p3); + + Value v1(obj_1); + Value v2(obj_2); + Value v3(obj_3); + + assert_eq(v1.type(), obj_type); + assert_eq(v1, v2); + assert_neq(v1, v3); + + assert_eq(v1.get_obj(), obj_1); + assert_eq(v3.get_obj(), obj_3); +} + +void test_array_value() { + Array array_1; + array_1.push_back(1); + array_1.push_back("2"); + Array array_2; + array_2.push_back(1); + array_2.push_back("2"); + Array array_3; + array_3.push_back(1); + array_3.push_back("X"); + + Value v1(array_1); + Value v2(array_2); + Value v3(array_3); + + assert_eq(v1.type(), array_type); + assert_eq(v1, v2); + assert_neq(v1, v3); + + assert_eq(v1.get_array(), array_1); + assert_eq(v3.get_array(), array_3); +} + +void test_bool_value() { + Value v1(true); + Value v2(true); + Value v3(false); + + assert_eq(v1.type(), bool_type); + assert_eq(v1, v2); + assert_neq(v1, v3); + + assert(v1.get_bool()); + assert(!v3.get_bool()); +} + +void test_int_value() { + Value v1(1); + Value v2(1); + Value v3(INT_MAX); + + assert_eq(v1.type(), int_type); + assert_eq(v1, v2); + assert_neq(v1, v3); + + unsigned int uint_max = INT_MAX; + + assert_eq(v1.get_int(), 1); + assert_eq(v1.get_int64(), 1); + assert_eq(v1.get_uint64(), 1u); + assert_eq(v3.get_int(), INT_MAX); + assert_eq(v3.get_int64(), INT_MAX); + assert_eq(v3.get_uint64(), uint_max); + + Value v4(max_int64); + + assert_eq(v4.get_int64(), max_int64); + assert_eq(v4.get_uint64(), static_cast(max_int64)); + + const uint64_t max_int64_plus_1 = max_int64 + uint64_t(1); + + Value v5(max_int64_plus_1); + + assert_eq(v5.get_uint64(), max_int64_plus_1); + + Value v6(max_uint64); + + assert_eq(v6.get_uint64(), max_uint64); + + Value v7(0); + + assert_eq(v7.get_int(), 0); + assert_eq(v7.get_int64(), 0); + assert_eq(v7.get_uint64(), 0u); + + Value v8(-1); + + assert_eq(v8.get_int(), -1); + assert_eq(v8.get_int64(), -1); + assert_eq(v8.get_uint64(), max_uint64); +} + +void test_real_value() { + Value v1(1.0); + Value v2(1.0); + Value v3(2.0); + + assert_eq(v1.type(), real_type); + assert_eq(v1, v2); + assert_neq(v1, v3); + + assert_eq(v1.get_real(), 1.0); + assert_eq(v3.get_real(), 2.0); +} + +void test_null_value() { + Value v1; + Value v2; + + assert_eq(v1.type(), null_type); + assert_eq(v1.is_null(), true); + assert_eq(v1, v2); + assert_eq(v1.is_null(), true); + assert_eq(Value(1).is_null(), false); +} + +template +void test_get_value(const T& t) { + assert_eq(Value(t).get_value(), t); +} + +void test_get_value() { + test_get_value(123); + test_get_value(max_int64); + test_get_value(1.23); + test_get_value(true); + test_get_value(false); + test_get_value(string("test")); + + Array a; + a.push_back(1); + a.push_back("2"); + + test_get_value(a); + + Object obj; + obj.push_back(Pair("name1", "value1")); + + test_get_value(obj); +} + +void assert_array_eq(const Value& v, const Array& a) { assert_eq(v.get_array(), a); } + +void assert_obj_eq(const Value& v, const Object& obj) { assert_eq(v.get_obj(), obj); } + +template +void check_copy(const T& t) { + const Value v1(t); + const Value v2(v1); + Value v3; + v3 = v1; + + assert_eq(v1, v2); + assert_eq(v1, v3); + + assert_eq(v2.get_value(), t); + assert_eq(v3.get_value(), t); + + assert_eq(v1.is_uint64(), v2.is_uint64()); + assert_eq(v1.is_uint64(), v3.is_uint64()); +} + +void check_copying_null() { + const Value v1; + const Value v2(v1); + Value v3; + v3 = v1; + + assert_eq(v2.type(), null_type); + assert_eq(v3.type(), null_type); +} + +void test_copying() { + { + const Array array_1 = list_of(1)(2); + + Value v1(array_1); + const Value v2(v1); + + assert_array_eq(v1, array_1); + assert_array_eq(v2, array_1); + + v1.get_array()[0] = 3; + + assert_array_eq(v1, list_of(3)(2)); + assert_array_eq(v2, array_1); + } + { + const Object obj_1 = list_of(Pair("a", 1))(Pair("b", 2)); + + Value v1(obj_1); + Value v2; + + v2 = v1; + + assert_obj_eq(v1, obj_1); + assert_obj_eq(v2, obj_1); + + v1.get_obj()[0] = Pair("c", 3); + + assert_obj_eq(v1, list_of(Pair("c", 3))(Pair("b", 2))); + assert_obj_eq(v2, obj_1); + } + { + check_copy(1); + check_copy(2.0); + check_copy(max_int64); + check_copy(max_uint64); + check_copy(string("test")); + check_copy(true); + check_copy(false); + const Array array_1 = list_of(1)(2); + check_copy(array_1); + const Object obj_1 = list_of(Pair("a", 1))(Pair("b", 2)); + check_copy(obj_1); + check_copying_null(); + } +} + +void test_obj_map_implemention() { +#ifdef JSON_SPIRIT_MVALUE_ENABLED + mObject obj; + + obj["name 1"] = 1; + obj["name 2"] = "two"; + + assert_eq(obj.size(), 2u); + + assert_eq(obj.find("name 1")->second.get_int(), 1); + assert_eq(obj.find("name 2")->second.get_str(), "two"); +#endif +} + +template +void check_an_int_is_a_real(Int i, bool expected_result) { + assert_eq(Value(i).is_uint64(), expected_result); +} + +void test_is_uint64() { + check_an_int_is_a_real(1, false); + check_an_int_is_a_real(static_cast(1), false); + check_an_int_is_a_real(static_cast(1), true); +} + +template +void check_an_int_is_a_real(Int i, double expected_result) { + assert_eq(Value(i).get_real(), expected_result); +} + +void test_an_int_is_a_real() { + check_an_int_is_a_real(-1, -1.0); + check_an_int_is_a_real(0, 0.0); + check_an_int_is_a_real(1, 1.0); + check_an_int_is_a_real(max_int64, 9223372036854775800.0); + check_an_int_is_a_real(max_uint64, 18446744073709552000.0); +} + +template +void check_wrong_type_exceptions(const Value& v, const string& requested_type_name, + const string& actual_type_name) { + try { + v.get_value(); + + assert(false); + } catch (const runtime_error& e) { + ostringstream os; + + os << "get_value< " << requested_type_name << " > called on " + << actual_type_name << " Value"; + + assert_eq(e.what(), os.str()); + } +} + +template +void check_wrong_type_exceptions(const string& requested_type_name) { + Value v; + + assert_eq(v.type(), null_type); + + check_wrong_type_exceptions(v, requested_type_name, "null"); +} + +void test_wrong_type_exceptions() { + check_wrong_type_exceptions("Object"); + check_wrong_type_exceptions("Array"); + check_wrong_type_exceptions("string"); + check_wrong_type_exceptions("boolean"); + check_wrong_type_exceptions("integer"); + check_wrong_type_exceptions("integer"); + check_wrong_type_exceptions("real"); + + Value v("string"); + + assert_eq(v.type(), str_type); + + check_wrong_type_exceptions(v, "real", "string"); +} +#endif + +template +class Container_constructor_runner { +public: + Container_constructor_runner() { + vector vd = list_of(1.2)(1.3); + test_container_constructor(vd); + + vector vi = list_of(1); + test_container_constructor(vi); + + vector vi2 = list_of(1)(2); + test_container_constructor(vi2); + + vector vi3 = list_of(1)(2)(3); + test_container_constructor(vi3); + + list ld = list_of(1.2)(1.3); + test_container_constructor(ld); + + list li = list_of(1); + test_container_constructor(li); + + list li2 = list_of(1)(2); + test_container_constructor(li2); + + list li3 = list_of(1)(2)(3); + test_container_constructor(li3); + } + +private: + typedef typename Config_type::Array_type Array_type; + typedef typename Config_type::Value_type Value_type; + + template + void test_container_constructor(const Cont& cont) { + typedef typename Cont::value_type Cont_value_type; + const Value_type val(cont.begin(), cont.end()); + const Array_type& arr = val.get_array(); + Cont result; + for (unsigned int i = 0; i < arr.size(); ++i) { + result.push_back(arr[i].template get_value()); + } + assert_eq(result, cont); + } +}; + +void test_container_constructor() { +#ifdef JSON_SPIRIT_VALUE_ENABLED + Container_constructor_runner(); +#endif +#ifdef JSON_SPIRIT_MVALUE_ENABLED + Container_constructor_runner(); +#endif +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Container_constructor_runner(); +#endif +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Container_constructor_runner(); +#endif +} + +template +class Variant_constructor_runner { +public: + Variant_constructor_runner() { + test_variant_constructor >(1.23); + test_variant_constructor >(123); + test_variant_constructor >( + to_str("foo")); + test_variant_constructor >(true); + test_variant_constructor< + variant >( + boost::int64_t(123)); + test_variant_constructor< + variant >( + boost::uint64_t(123)); + + { + variant variant = Null(); + const Value_type val(variant); + assert(val.is_null()); + } + + vector vd = list_of(1.2)(1.3); + test_variant_array_constructor(vd); + + vector vi = list_of(1); + test_variant_array_constructor(vi); + + vector vi2 = list_of(1)(2); + test_variant_array_constructor(vi2); + + vector vi3 = list_of(1)(2)(3); + test_variant_array_constructor(vi3); + + list ld = list_of(1.2)(1.3); + test_variant_array_constructor(ld); + + list li = list_of(1); + test_variant_array_constructor(li); + + list li2 = list_of(1)(2); + test_variant_array_constructor(li2); + + list li3 = list_of(1)(2)(3); + test_variant_array_constructor(li3); + } + +private: + typedef typename Config_type::String_type String_type; + typedef typename Config_type::Array_type Array_type; + typedef typename Config_type::Value_type Value_type; + + template + void test_variant_constructor(const T& t) { + const Variant_t variant(t); + const Value_type val(variant); + assert_eq(val.template get_value(), t); + } + + template class Cont> + void test_variant_array_constructor(const Cont& cont) { + const variant > variant = cont; + const Value_type val(variant); + const Array_type& arr = val.get_array(); + Cont result; + for (unsigned int i = 0; i < arr.size(); ++i) { + result.push_back(arr[i].template get_value()); + } + assert_eq(result, cont); + } +}; + +void test_variant_constructor() { +#ifdef JSON_SPIRIT_VALUE_ENABLED + Variant_constructor_runner(); +#endif +#ifdef JSON_SPIRIT_MVALUE_ENABLED + Variant_constructor_runner(); + +#endif +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Variant_constructor_runner(); +#endif +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Variant_constructor_runner(); +#endif +} +} // namespace + +void json5_parser::test_value() { +#ifdef JSON_SPIRIT_VALUE_ENABLED + Object obj; + Value value_str("value"); + Value value_obj(obj); + Value value_bool(true); + + Value value_str_2(string("value")); + Value value_obj_2(obj); + Value value_bool_2(false); + + const char* str("value"); + Value value_str_2b(str); + + assert_eq(value_str, value_str); + assert_eq(value_str, value_str_2); + assert_eq(value_str, value_str_2b); + assert_eq(value_obj, value_obj); + assert_eq(value_obj, value_obj_2); + assert_neq(value_str, value_obj); + assert_neq(value_str, value_bool); + + Object obj_2; + obj_2.push_back(Pair("name", value_str)); + Value value_str_3("xxxxx"); + Value value_obj_3(obj_2); + + assert_neq(value_str, value_str_3); + assert_neq(value_obj, value_obj_3); + + test_obj_value(); + test_array_value(); + test_bool_value(); + test_int_value(); + test_real_value(); + test_null_value(); + test_get_value(); + test_copying(); + test_obj_map_implemention(); + test_is_uint64(); + test_an_int_is_a_real(); + test_wrong_type_exceptions(); +#endif + test_container_constructor(); + test_variant_constructor(); +} diff --git a/json_test/json5_parser_value_test.h b/json_test/json5_parser_value_test.h index a9c1391..3751d7d 100644 --- a/json_test/json5_parser_value_test.h +++ b/json_test/json5_parser_value_test.h @@ -1,18 +1,17 @@ -#ifndef JSON_SPIRIT_VALUE_TEST -#define JSON_SPIRIT_VALUE_TEST - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -namespace json5_parser -{ - void test_value(); -} - -#endif +#ifndef JSON_SPIRIT_VALUE_TEST +#define JSON_SPIRIT_VALUE_TEST + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +namespace json5_parser { +void test_value(); +} + +#endif diff --git a/json_test/json5_parser_writer_test.cpp b/json_test/json5_parser_writer_test.cpp index 34395a2..46f7fb7 100644 --- a/json_test/json5_parser_writer_test.cpp +++ b/json_test/json5_parser_writer_test.cpp @@ -1,788 +1,783 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_writer_test.h" -#include "utils_test.h" -#include "json5_parser_writer.h" -#include "json5_parser_value.h" - -#include -#include - -using namespace json5_parser; -using namespace std; -using namespace boost; - -namespace -{ - const int64_t max_int64 = integer_traits< int64_t >::max(); - const uint64_t max_uint64 = integer_traits< uint64_t >::max(); - - template< class Config_type > - struct Test_runner - { - typedef typename Config_type::String_type String_type; - typedef typename Config_type::Object_type Object_type; - typedef typename Config_type::Array_type Array_type; - typedef typename Config_type::Value_type Value_type; - typedef typename String_type::value_type Char_type; - typedef typename String_type::const_iterator Iter_type; - typedef std::basic_ostream< Char_type > Ostream_type; - - String_type to_str( const char* c_str ) - { - return ::to_str< String_type >( c_str ); - } - - String_type zero_str() - { -#ifdef WIN32 - return to_str( "0.00000000000000000" ); -#else - return to_str( "0.0000000000000000" ); -#endif - } - - void add_value( Object_type& obj, const char* c_name, const Value_type& value ) - { - Config_type::add( obj, to_str( c_name ), value ); - } - - void add_c_str( Object_type& obj, const char* c_name, const char* c_value ) - { - add_value( obj, c_name, to_str( c_value ) ); - } - - void check_eq( const Value_type& value, const String_type& expected_result ) - { - assert_eq( write( value ), expected_result ); - } - - void check_eq( const Value_type& value, const char* expected_result ) - { - check_eq( value, to_str( expected_result ) ); - } - - void check_eq_pretty( const Value_type& value, const char* expected_result ) - { - assert_eq( write_formatted( value ), to_str( expected_result ) ); - assert_eq( write( value, pretty_print ), to_str( expected_result ) ); - } - - void check_eq_single_line_arrays( const Value_type& value, const char* expected_result ) - { - assert_eq( write( value, single_line_arrays ), to_str( expected_result ) ); - } - - void check_eq( const Value_type& value, const String_type& expected_result , Output_options options ) - { - assert_eq( write( value, options ), expected_result ); - } - - void check_eq( const Value_type& value, const char* expected_result, Output_options options ) - { - check_eq( value, to_str( expected_result ), options ); - } - - void test_empty_obj() - { - check_eq( Object_type(), "{}" ); - check_eq_pretty( Object_type(), "{\n}" ); - } - - void test_obj_with_one_member() - { - Object_type obj; - - add_c_str( obj, "name", "value" ); - - check_eq ( obj, "{\"name\":\"value\"}" ); - check_eq_pretty( obj, "{\n" - " \"name\" : \"value\"\n" - "}" ); - } - - void test_obj_with_two_members() - { - Object_type obj; - - add_c_str( obj, "name_1", "value_1" ); - add_c_str( obj, "name_2", "value_2" ); - - check_eq( obj, "{\"name_1\":\"value_1\",\"name_2\":\"value_2\"}" ); - - check_eq_pretty( obj, "{\n" - " \"name_1\" : \"value_1\",\n" - " \"name_2\" : \"value_2\"\n" - "}" ); - } - - void test_obj_with_three_members() - { - Object_type obj; - - add_c_str( obj, "name_1", "value_1" ); - add_c_str( obj, "name_2", "value_2" ); - add_c_str( obj, "name_3", "value_3" ); - - check_eq( obj, "{\"name_1\":\"value_1\",\"name_2\":\"value_2\",\"name_3\":\"value_3\"}" ); - - check_eq_pretty( obj, "{\n" - " \"name_1\" : \"value_1\",\n" - " \"name_2\" : \"value_2\",\n" - " \"name_3\" : \"value_3\"\n" - "}" ); - } - - void test_obj_with_one_empty_child_obj() - { - Object_type child; - - Object_type root; - - add_value( root, "child", child ); - - check_eq( root, "{\"child\":{}}" ); - - check_eq_pretty( root, "{\n" - " \"child\" : {\n" - " }\n" - "}" ); - } - - void test_obj_with_one_child_obj() - { - Object_type child; - - add_c_str( child, "name_2", "value_2" ); - - Object_type root; - - add_value( root, "child", child ); - add_c_str( root, "name_1", "value_1" ); - - check_eq( root, "{\"child\":{\"name_2\":\"value_2\"},\"name_1\":\"value_1\"}" ); - - check_eq_pretty( root, "{\n" - " \"child\" : {\n" - " \"name_2\" : \"value_2\"\n" - " },\n" - " \"name_1\" : \"value_1\"\n" - "}" ); - } - - void test_obj_with_grandchild_obj() - { - Object_type child_1; add_c_str( child_1, "name_1", "value_1" ); - Object_type child_2; - Object_type child_3; add_c_str( child_3, "name_3", "value_3" ); - - add_value( child_2, "grandchild", child_3 ); - add_c_str( child_2, "name_2", "value_2" ); - - Object_type root; - - add_value( root, "child_1", child_1 ); - add_value( root, "child_2", child_2 ); - add_c_str( root, "name_a", "value_a" ); - add_c_str( root, "name_b", "value_b" ); - - check_eq( root, "{\"child_1\":{\"name_1\":\"value_1\"}," - "\"child_2\":{\"grandchild\":{\"name_3\":\"value_3\"},\"name_2\":\"value_2\"}," - "\"name_a\":\"value_a\"," - "\"name_b\":\"value_b\"}" ); - - check_eq_pretty( root, "{\n" - " \"child_1\" : {\n" - " \"name_1\" : \"value_1\"\n" - " },\n" - " \"child_2\" : {\n" - " \"grandchild\" : {\n" - " \"name_3\" : \"value_3\"\n" - " },\n" - " \"name_2\" : \"value_2\"\n" - " },\n" - " \"name_a\" : \"value_a\",\n" - " \"name_b\" : \"value_b\"\n" - "}" ); - } - - void test_objs_with_bool_pairs() - { - Object_type obj; - - add_value( obj, "name_1", true ); - add_value( obj, "name_2", false ); - add_value( obj, "name_3", true ); - - check_eq( obj, "{\"name_1\":true,\"name_2\":false,\"name_3\":true}" ); - } - - void test_objs_with_int_pairs() - { - Object_type obj; - - add_value( obj, "name_1", 11 ); - add_value( obj, "name_2", INT_MAX ); - add_value( obj, "name_3", max_int64 ); - - ostringstream os; - - os << "{\"name_1\":11,\"name_2\":" << INT_MAX << ",\"name_3\":" << max_int64 << "}"; - - check_eq( obj, os.str().c_str() ); - } - - void test_objs_with_real_pairs() - { - Object_type obj; - - add_value( obj, "name_1", 0.0 ); - add_value( obj, "name_2", 1.234567890123456789e-108 ); - add_value( obj, "name_3", -1234567890.123456789 ); - add_value( obj, "name_4", -1.2e-126 ); - - check_eq( obj, to_str( "{\"name_1\":0," - "\"name_2\":1.2345678901234567e-108," - "\"name_3\":-1234567890.1234567," - "\"name_4\":-1.2e-126}" ) ); - } - - void test_objs_with_null_pairs() - { - Object_type obj; - - add_value( obj, "name_1", Value_type::null ); - add_value( obj, "name_2", Value_type::null ); - add_value( obj, "name_3", Value_type::null ); - - check_eq( obj, "{\"name_1\":null,\"name_2\":null,\"name_3\":null}" ); - } - - void test_empty_array() - { - check_eq( Array_type(), "[]" ); - check_eq_pretty( Array_type(), "[\n" - "]" ); - check_eq_single_line_arrays( Array_type(), "[ ]" ); - } - - void test_array_with_one_member() - { - Array_type arr; - - arr.push_back( to_str( "value" ) ); - - check_eq ( arr, "[\"value\"]" ); - check_eq_pretty( arr, "[\n" - " \"value\"\n" - "]" ); - check_eq_single_line_arrays( arr, "[ \"value\" ]" ); - } - - void test_array_with_two_members() - { - Array_type arr; - - arr.push_back( to_str( "value_1" ) ); - arr.push_back( 1 ); - - check_eq ( arr, "[\"value_1\",1]" ); - check_eq_pretty( arr, "[\n" - " \"value_1\",\n" - " 1\n" - "]" ); - check_eq_single_line_arrays( arr, "[ \"value_1\", 1 ]" ); - } - - void test_array_with_n_members() - { - Array_type arr; - - arr.push_back( to_str( "value_1" ) ); - arr.push_back( 123 ); - arr.push_back( 123.456 ); - arr.push_back( true ); - arr.push_back( false ); - arr.push_back( Value_type() ); - - check_eq ( arr, "[\"value_1\",123,123.456,true,false,null]" ); - check_eq_pretty( arr, "[\n" - " \"value_1\",\n" - " 123,\n" - " 123.456,\n" - " true,\n" - " false,\n" - " null\n" - "]" ); - check_eq_single_line_arrays( arr, "[ \"value_1\", 123, 123.456, true, false, null ]" ); - } - - void test_array_with_one_empty_child_array() - { - Array_type arr; - - arr.push_back( Array_type() ); - - check_eq ( arr, "[[]]" ); - check_eq_pretty( arr, "[\n" - " [\n" - " ]\n" - "]" ); - check_eq_single_line_arrays( arr, "[\n" - " [ ]\n" - "]" ); - } - - void test_array_with_one_child_array() - { - Array_type child; - - child.push_back( 2 ); - - Array_type root; - - root.push_back( 1 ); - root.push_back( child ); - - check_eq ( root, "[1,[2]]" ); - check_eq_pretty( root, "[\n" - " 1,\n" - " [\n" - " 2\n" - " ]\n" - "]" ); - check_eq_single_line_arrays( root, "[\n" - " 1,\n" - " [ 2 ]\n" - "]" ); - } - - void test_array_with_grandchild_array() - { - Array_type child_1; child_1.push_back( 11 ); - Array_type child_2; child_2.push_back( 22 ); - Array_type child_3; child_3.push_back( 33 ); - - child_2.push_back( child_3 ); - - Array_type root; - - root.push_back( 1); - root.push_back( child_1 ); - root.push_back( child_2 ); - root.push_back( 2 ); - - check_eq ( root, "[1,[11],[22,[33]],2]" ); - check_eq_pretty( root, "[\n" - " 1,\n" - " [\n" - " 11\n" - " ],\n" - " [\n" - " 22,\n" - " [\n" - " 33\n" - " ]\n" - " ],\n" - " 2\n" - "]" ); - check_eq_single_line_arrays( root, "[\n" - " 1,\n" - " [ 11 ],\n" - " [\n" - " 22,\n" - " [ 33 ]\n" - " ],\n" - " 2\n" - "]" ); - } - - void test_array_and_objs() - { - Array_type a; - - a.push_back( 11 ); - - Object_type obj; - - add_value( obj, "a", 1 ); - - a.push_back( obj ); - - check_eq ( a, "[11,{\"a\":1}]" ); - check_eq_pretty( a, "[\n" - " 11,\n" - " {\n" - " \"a\" : 1\n" - " }\n" - "]" ); - check_eq_single_line_arrays( a, "[\n" - " 11,\n" - " {\n" - " \"a\" : 1\n" - " }\n" - "]" ); - - add_value( obj, "b", 2 ); - - a.push_back( 22 ); - a.push_back( 33 ); - a.push_back( obj ); - - check_eq ( a, "[11,{\"a\":1},22,33,{\"a\":1,\"b\":2}]" ); - check_eq_pretty( a, "[\n" - " 11,\n" - " {\n" - " \"a\" : 1\n" - " },\n" - " 22,\n" - " 33,\n" - " {\n" - " \"a\" : 1,\n" - " \"b\" : 2\n" - " }\n" - "]" ); - check_eq_single_line_arrays( a, "[\n" - " 11,\n" - " {\n" - " \"a\" : 1\n" - " },\n" - " 22,\n" - " 33,\n" - " {\n" - " \"a\" : 1,\n" - " \"b\" : 2\n" - " }\n" - "]" ); - } - - void test_obj_and_arrays() - { - Object_type obj; - - add_value( obj, "a", 1 ); - - Array_type a; - - a.push_back( 11 ); - a.push_back( 12 ); - - add_value( obj, "b", a ); - - check_eq ( obj, "{\"a\":1,\"b\":[11,12]}" ); - check_eq_pretty( obj, "{\n" - " \"a\" : 1,\n" - " \"b\" : [\n" - " 11,\n" - " 12\n" - " ]\n" - "}" ); - check_eq_single_line_arrays( obj, "{\n" - " \"a\" : 1,\n" - " \"b\" : [ 11, 12 ]\n" - "}" ); - - a.push_back( obj ); - - add_value( obj, "c", a ); - - check_eq ( obj, "{\"a\":1,\"b\":[11,12],\"c\":[11,12,{\"a\":1,\"b\":[11,12]}]}" ); - check_eq_pretty( obj, "{\n" - " \"a\" : 1,\n" - " \"b\" : [\n" - " 11,\n" - " 12\n" - " ],\n" - " \"c\" : [\n" - " 11,\n" - " 12,\n" - " {\n" - " \"a\" : 1,\n" - " \"b\" : [\n" - " 11,\n" - " 12\n" - " ]\n" - " }\n" - " ]\n" - "}" ); - check_eq_single_line_arrays( obj, "{\n" - " \"a\" : 1,\n" - " \"b\" : [ 11, 12 ],\n" - " \"c\" : [\n" - " 11,\n" - " 12,\n" - " {\n" - " \"a\" : 1,\n" - " \"b\" : [ 11, 12 ]\n" - " }\n" - " ]\n" - "}" ); - } - - void test_escape_char( const char* esc_str_in, const char* esc_str_out, Output_options options = none ) - { - Object_type obj; - - const string name_str( string( esc_str_in ) + "name" ); - - add_value( obj, name_str.c_str(), to_str( "value" ) + to_str( esc_str_in ) ); - - const string out_str( string( "{\"" ) + esc_str_out + "name\":\"value" + esc_str_out + "\"}" ); - - check_eq( obj, out_str.c_str(), options ); - } - - void test_escape_chars() - { - test_escape_char( "\r", "\\r" ); - test_escape_char( "\n", "\\n" ); - test_escape_char( "\t", "\\t" ); - test_escape_char( "\f", "\\f" ); - test_escape_char( "\b", "\\b" ); - test_escape_char( "\"", "\\\"" ); - test_escape_char( "\\", "\\\\" ); - test_escape_char( "\x01", "\\u0001" ); - test_escape_char( "\x12", "\\u0012" ); - test_escape_char( "\x7F", "\\u007F" ); - } - - void test_disabling_nonprintable_esc_chars() - { - test_escape_char( "\t", "\\t", raw_utf8 ); - test_escape_char( "\x01", "\x01", raw_utf8 ); - test_escape_char( "\x01\x12", "\x01\x12", raw_utf8 ); - } - - void test_to_stream() - { - basic_ostringstream< Char_type > os; - - Array_type arr; - - arr.push_back( 111 ); - arr.push_back( 222 ); - - os << hex; // the code should handle this, i.e. output decimal - - write( arr, os ); - - assert_eq( os.str(), to_str( "[111,222]" ) ); - } - - void test_values() - { - check_eq( 123, "123" ); - check_eq( 1.234, "1.234" ); - check_eq( to_str( "abc" ), "\"abc\"" ); - check_eq( false, "false" ); - check_eq( Value_type::null, "null" ); - } - - void test_uint64() - { - check_eq( Value_type( 0 ), "0" ); - check_eq( Value_type( int64_t( 0 ) ), "0" ); - check_eq( Value_type( uint64_t( 0 ) ), "0" ); - - check_eq( Value_type( 1 ), "1" ); - check_eq( Value_type( int64_t( 1 ) ), "1" ); - check_eq( Value_type( uint64_t( 1 ) ), "1" ); - - check_eq( Value_type( -1 ), "-1" ); - check_eq( Value_type( int64_t( -1 ) ), "-1" ); - - check_eq( Value_type( max_int64 ), "9223372036854775807" ); - check_eq( Value_type( uint64_t( max_int64 ) ), "9223372036854775807" ); - - check_eq( Value_type( max_uint64 ), "18446744073709551615" ); - } - - void test_ios_state_saved() - { - basic_ostringstream< Char_type > os; - - os << 0.123456789; - - Array_type arr; - - arr.push_back( 0.123456789 ); - - write( arr, os ); - - os << 0.123456789; - - assert_eq( os.str(), to_str( "0.123457" - "[0.123456789]" - "0.123457" ) ); - } - - void check_remove_trailing_zeros( const double value, const String_type& expected_str_with, const String_type& expected_str_without ) - { - check_eq( value, expected_str_with, none ); - check_eq( value, expected_str_without, remove_trailing_zeros ); - } - - void check_remove_trailing_zeros( const double value, const char* expected_str_with, const char* expected_str_without ) - { - check_remove_trailing_zeros( value, to_str( expected_str_with ), to_str( expected_str_without ) ); - } - - void test_remove_trailing_zeros() - { -#ifdef WIN32 - const String_type exp = to_str( "099" ); -#else - const String_type exp = to_str( "99" ); -#endif - check_remove_trailing_zeros( 0.0, "0", "0" ); - check_remove_trailing_zeros( 1.2, "1.2", "1.2" ); - check_remove_trailing_zeros( 0.123456789, "0.123456789", "0.123456789" ); - check_remove_trailing_zeros( 1.2e-99, to_str( "1.2e-" ) + exp, to_str( "1.2e-" ) + exp ); - check_remove_trailing_zeros( 1.23456789e99, to_str( "1.2345678900000001e+" ) + exp, to_str( "1.23456789e+" ) + exp ); - } - - void check_precision_of_doubles( unsigned int precision, const char* expected_result_1, const char* expected_result_2 = 0 ) - { - Value_type val = 0.1234567890123456789; - assert_eq( write( val, none, precision ), to_str( expected_result_1 ) ); - if( !expected_result_2 ) - { - expected_result_2 = expected_result_1; - } - assert_eq( write( val, remove_trailing_zeros, precision ), to_str( expected_result_2 ) ); - } - - void check_precision_of_doubles( const char* expected_result_1, const char* expected_result_2 ) - { - Value_type val = 0.1234567890123456789; - assert_eq( write( val, none ), to_str( expected_result_1 ) ); - assert_eq( write( val, remove_trailing_zeros ), to_str( expected_result_2 ) ); - } - - void test_precision_of_doubles() - { - // default is 17, or 16 for remove_trailing_zeros flag - check_precision_of_doubles( "0.12345678901234568", "0.1234567890123457" ); - check_precision_of_doubles( 0, "0.12345678901234568", "0.1234567890123457" ); - - // specified override is used with or without remove_trailing_zeros flag - check_precision_of_doubles( 9, "0.123456789" ); - check_precision_of_doubles( 6, "0.123457" ); - check_precision_of_doubles( 1, "0.1" ); - } - - void test_multiple_options() - { - Value value; - write(value, always_escape_nonascii | pretty_print ); - } - - void run_tests() - { - test_empty_obj(); - test_obj_with_one_member(); - test_obj_with_two_members(); - test_obj_with_three_members(); - test_obj_with_one_empty_child_obj(); - test_obj_with_one_child_obj(); - test_obj_with_grandchild_obj(); - test_objs_with_bool_pairs(); - test_objs_with_int_pairs(); - test_objs_with_real_pairs(); - test_objs_with_null_pairs(); - test_empty_array(); - test_array_with_one_member(); - test_array_with_two_members(); - test_array_with_n_members(); - test_array_with_one_empty_child_array(); - test_array_with_one_child_array(); - test_array_with_grandchild_array(); - test_array_and_objs(); - test_obj_and_arrays(); - test_escape_chars(); - test_disabling_nonprintable_esc_chars(); - test_to_stream(); - test_values(); - test_uint64(); - test_ios_state_saved(); - test_remove_trailing_zeros(); - test_precision_of_doubles(); - test_multiple_options(); - } - }; - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void test_always_esc_nonascii() - { - if( iswprint( L'\x05DE' ) ) - { - const wstring s( L"\x05DE\x05E9\x05EA\x05DE\x05E9" ); - - wArray arr( 1, s ); - - const wstring foo = arr[0].get_str(); - - const wstring json_raw = write( arr ); - - assert_eq( json_raw, L"[\"" + s + L"\"]" ); - - const wstring json_escaped = write( arr, always_escape_nonascii ); - - assert_eq( json_escaped, L"[\"\\u05DE\\u05E9\\u05EA\\u05DE\\u05E9\"]" ); - } - } - - void test_wide_esc_u( wchar_t c, const wstring& result) - { - const wstring s( 1, c ); - - wArray arr( 1, s ); - - assert_eq( write( arr ), L"[\"\\u" + result + L"\"]" ); - } - - void test_wide_esc_u() - { - test_wide_esc_u( 0xABCD, L"ABCD" ); - test_wide_esc_u( 0xFFFF, L"FFFF" ); - } -#endif - - bool is_printable( char c ) - { - const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c ); - - return iswprint( unsigned_c ) != 0; - } - -#ifdef JSON_SPIRIT_VALUE_ENABLED - void test_extended_ascii() - { - const string expeced_result( is_printable( '\xE4' ) ? "[\"\xE4\xF6\xFC\xDF\"]" : "[\"\\u00E4\\u00F6\\u00FC\\u00DF\"]" ); - - assert_eq( write( Array( 1, "\xE4\xF6\xFC\xDF" ) ), expeced_result ); - } -#endif -} - -void json5_parser::test_writer() -{ -#ifdef JSON_SPIRIT_VALUE_ENABLED - Test_runner< Config >().run_tests(); - test_extended_ascii(); -#endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED - Test_runner< mConfig >().run_tests(); -#endif -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Test_runner< wConfig >().run_tests(); - test_wide_esc_u(); - test_always_esc_nonascii(); -#endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Test_runner< wmConfig >().run_tests(); -#endif -} +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_writer_test.h" +#include "json5_parser_value.h" +#include "json5_parser_writer.h" +#include "utils_test.h" + +#include +#include + +using namespace json5_parser; +using namespace std; +using namespace boost; + +namespace { +const int64_t max_int64 = integer_traits::max(); +const uint64_t max_uint64 = integer_traits::max(); + +template +struct Test_runner { + typedef typename Config_type::String_type String_type; + typedef typename Config_type::Object_type Object_type; + typedef typename Config_type::Array_type Array_type; + typedef typename Config_type::Value_type Value_type; + typedef typename String_type::value_type Char_type; + typedef typename String_type::const_iterator Iter_type; + typedef std::basic_ostream Ostream_type; + + String_type to_str(const char* c_str) { return ::to_str(c_str); } + + String_type zero_str() { +#ifdef WIN32 + return to_str("0.00000000000000000"); +#else + return to_str("0.0000000000000000"); +#endif + } + + void add_value(Object_type& obj, const char* c_name, const Value_type& value) { + Config_type::add(obj, to_str(c_name), value); + } + + void add_c_str(Object_type& obj, const char* c_name, const char* c_value) { + add_value(obj, c_name, to_str(c_value)); + } + + void check_eq(const Value_type& value, const String_type& expected_result) { + assert_eq(write(value), expected_result); + } + + void check_eq(const Value_type& value, const char* expected_result) { + check_eq(value, to_str(expected_result)); + } + + void check_eq_pretty(const Value_type& value, const char* expected_result) { + assert_eq(write_formatted(value), to_str(expected_result)); + assert_eq(write(value, pretty_print), to_str(expected_result)); + } + + void check_eq_single_line_arrays(const Value_type& value, + const char* expected_result) { + assert_eq(write(value, single_line_arrays), to_str(expected_result)); + } + + void check_eq(const Value_type& value, const String_type& expected_result, + Output_options options) { + assert_eq(write(value, options), expected_result); + } + + void check_eq(const Value_type& value, const char* expected_result, + Output_options options) { + check_eq(value, to_str(expected_result), options); + } + + void test_empty_obj() { + check_eq(Object_type(), "{}"); + check_eq_pretty(Object_type(), "{\n}"); + } + + void test_obj_with_one_member() { + Object_type obj; + + add_c_str(obj, "name", "value"); + + check_eq(obj, "{\"name\":\"value\"}"); + check_eq_pretty(obj, + "{\n" + " \"name\" : \"value\"\n" + "}"); + } + + void test_obj_with_two_members() { + Object_type obj; + + add_c_str(obj, "name_1", "value_1"); + add_c_str(obj, "name_2", "value_2"); + + check_eq(obj, "{\"name_1\":\"value_1\",\"name_2\":\"value_2\"}"); + + check_eq_pretty(obj, + "{\n" + " \"name_1\" : \"value_1\",\n" + " \"name_2\" : \"value_2\"\n" + "}"); + } + + void test_obj_with_three_members() { + Object_type obj; + + add_c_str(obj, "name_1", "value_1"); + add_c_str(obj, "name_2", "value_2"); + add_c_str(obj, "name_3", "value_3"); + + check_eq(obj, + "{\"name_1\":\"value_1\",\"name_2\":\"value_2\",\"name_3\":\"value_" + "3\"}"); + + check_eq_pretty(obj, + "{\n" + " \"name_1\" : \"value_1\",\n" + " \"name_2\" : \"value_2\",\n" + " \"name_3\" : \"value_3\"\n" + "}"); + } + + void test_obj_with_one_empty_child_obj() { + Object_type child; + + Object_type root; + + add_value(root, "child", child); + + check_eq(root, "{\"child\":{}}"); + + check_eq_pretty(root, + "{\n" + " \"child\" : {\n" + " }\n" + "}"); + } + + void test_obj_with_one_child_obj() { + Object_type child; + + add_c_str(child, "name_2", "value_2"); + + Object_type root; + + add_value(root, "child", child); + add_c_str(root, "name_1", "value_1"); + + check_eq(root, "{\"child\":{\"name_2\":\"value_2\"},\"name_1\":\"value_1\"}"); + + check_eq_pretty(root, + "{\n" + " \"child\" : {\n" + " \"name_2\" : \"value_2\"\n" + " },\n" + " \"name_1\" : \"value_1\"\n" + "}"); + } + + void test_obj_with_grandchild_obj() { + Object_type child_1; + add_c_str(child_1, "name_1", "value_1"); + Object_type child_2; + Object_type child_3; + add_c_str(child_3, "name_3", "value_3"); + + add_value(child_2, "grandchild", child_3); + add_c_str(child_2, "name_2", "value_2"); + + Object_type root; + + add_value(root, "child_1", child_1); + add_value(root, "child_2", child_2); + add_c_str(root, "name_a", "value_a"); + add_c_str(root, "name_b", "value_b"); + + check_eq(root, + "{\"child_1\":{\"name_1\":\"value_1\"}," + "\"child_2\":{\"grandchild\":{\"name_3\":\"value_3\"},\"name_2\":" + "\"value_2\"}," + "\"name_a\":\"value_a\"," + "\"name_b\":\"value_b\"}"); + + check_eq_pretty(root, + "{\n" + " \"child_1\" : {\n" + " \"name_1\" : \"value_1\"\n" + " },\n" + " \"child_2\" : {\n" + " \"grandchild\" : {\n" + " \"name_3\" : \"value_3\"\n" + " },\n" + " \"name_2\" : \"value_2\"\n" + " },\n" + " \"name_a\" : \"value_a\",\n" + " \"name_b\" : \"value_b\"\n" + "}"); + } + + void test_objs_with_bool_pairs() { + Object_type obj; + + add_value(obj, "name_1", true); + add_value(obj, "name_2", false); + add_value(obj, "name_3", true); + + check_eq(obj, "{\"name_1\":true,\"name_2\":false,\"name_3\":true}"); + } + + void test_objs_with_int_pairs() { + Object_type obj; + + add_value(obj, "name_1", 11); + add_value(obj, "name_2", INT_MAX); + add_value(obj, "name_3", max_int64); + + ostringstream os; + + os << "{\"name_1\":11,\"name_2\":" << INT_MAX << ",\"name_3\":" << max_int64 + << "}"; + + check_eq(obj, os.str().c_str()); + } + + void test_objs_with_real_pairs() { + Object_type obj; + + add_value(obj, "name_1", 0.0); + add_value(obj, "name_2", 1.234567890123456789e-108); + add_value(obj, "name_3", -1234567890.123456789); + add_value(obj, "name_4", -1.2e-126); + + check_eq(obj, to_str("{\"name_1\":0," + "\"name_2\":1.2345678901234567e-108," + "\"name_3\":-1234567890.1234567," + "\"name_4\":-1.2e-126}")); + } + + void test_objs_with_null_pairs() { + Object_type obj; + + add_value(obj, "name_1", Value_type::null); + add_value(obj, "name_2", Value_type::null); + add_value(obj, "name_3", Value_type::null); + + check_eq(obj, "{\"name_1\":null,\"name_2\":null,\"name_3\":null}"); + } + + void test_empty_array() { + check_eq(Array_type(), "[]"); + check_eq_pretty(Array_type(), + "[\n" + "]"); + check_eq_single_line_arrays(Array_type(), "[ ]"); + } + + void test_array_with_one_member() { + Array_type arr; + + arr.push_back(to_str("value")); + + check_eq(arr, "[\"value\"]"); + check_eq_pretty(arr, + "[\n" + " \"value\"\n" + "]"); + check_eq_single_line_arrays(arr, "[ \"value\" ]"); + } + + void test_array_with_two_members() { + Array_type arr; + + arr.push_back(to_str("value_1")); + arr.push_back(1); + + check_eq(arr, "[\"value_1\",1]"); + check_eq_pretty(arr, + "[\n" + " \"value_1\",\n" + " 1\n" + "]"); + check_eq_single_line_arrays(arr, "[ \"value_1\", 1 ]"); + } + + void test_array_with_n_members() { + Array_type arr; + + arr.push_back(to_str("value_1")); + arr.push_back(123); + arr.push_back(123.456); + arr.push_back(true); + arr.push_back(false); + arr.push_back(Value_type()); + + check_eq(arr, "[\"value_1\",123,123.456,true,false,null]"); + check_eq_pretty(arr, + "[\n" + " \"value_1\",\n" + " 123,\n" + " 123.456,\n" + " true,\n" + " false,\n" + " null\n" + "]"); + check_eq_single_line_arrays(arr, + "[ \"value_1\", 123, 123.456, true, false, null ]"); + } + + void test_array_with_one_empty_child_array() { + Array_type arr; + + arr.push_back(Array_type()); + + check_eq(arr, "[[]]"); + check_eq_pretty(arr, + "[\n" + " [\n" + " ]\n" + "]"); + check_eq_single_line_arrays(arr, + "[\n" + " [ ]\n" + "]"); + } + + void test_array_with_one_child_array() { + Array_type child; + + child.push_back(2); + + Array_type root; + + root.push_back(1); + root.push_back(child); + + check_eq(root, "[1,[2]]"); + check_eq_pretty(root, + "[\n" + " 1,\n" + " [\n" + " 2\n" + " ]\n" + "]"); + check_eq_single_line_arrays(root, + "[\n" + " 1,\n" + " [ 2 ]\n" + "]"); + } + + void test_array_with_grandchild_array() { + Array_type child_1; + child_1.push_back(11); + Array_type child_2; + child_2.push_back(22); + Array_type child_3; + child_3.push_back(33); + + child_2.push_back(child_3); + + Array_type root; + + root.push_back(1); + root.push_back(child_1); + root.push_back(child_2); + root.push_back(2); + + check_eq(root, "[1,[11],[22,[33]],2]"); + check_eq_pretty(root, + "[\n" + " 1,\n" + " [\n" + " 11\n" + " ],\n" + " [\n" + " 22,\n" + " [\n" + " 33\n" + " ]\n" + " ],\n" + " 2\n" + "]"); + check_eq_single_line_arrays(root, + "[\n" + " 1,\n" + " [ 11 ],\n" + " [\n" + " 22,\n" + " [ 33 ]\n" + " ],\n" + " 2\n" + "]"); + } + + void test_array_and_objs() { + Array_type a; + + a.push_back(11); + + Object_type obj; + + add_value(obj, "a", 1); + + a.push_back(obj); + + check_eq(a, "[11,{\"a\":1}]"); + check_eq_pretty(a, + "[\n" + " 11,\n" + " {\n" + " \"a\" : 1\n" + " }\n" + "]"); + check_eq_single_line_arrays(a, + "[\n" + " 11,\n" + " {\n" + " \"a\" : 1\n" + " }\n" + "]"); + + add_value(obj, "b", 2); + + a.push_back(22); + a.push_back(33); + a.push_back(obj); + + check_eq(a, "[11,{\"a\":1},22,33,{\"a\":1,\"b\":2}]"); + check_eq_pretty(a, + "[\n" + " 11,\n" + " {\n" + " \"a\" : 1\n" + " },\n" + " 22,\n" + " 33,\n" + " {\n" + " \"a\" : 1,\n" + " \"b\" : 2\n" + " }\n" + "]"); + check_eq_single_line_arrays(a, + "[\n" + " 11,\n" + " {\n" + " \"a\" : 1\n" + " },\n" + " 22,\n" + " 33,\n" + " {\n" + " \"a\" : 1,\n" + " \"b\" : 2\n" + " }\n" + "]"); + } + + void test_obj_and_arrays() { + Object_type obj; + + add_value(obj, "a", 1); + + Array_type a; + + a.push_back(11); + a.push_back(12); + + add_value(obj, "b", a); + + check_eq(obj, "{\"a\":1,\"b\":[11,12]}"); + check_eq_pretty(obj, + "{\n" + " \"a\" : 1,\n" + " \"b\" : [\n" + " 11,\n" + " 12\n" + " ]\n" + "}"); + check_eq_single_line_arrays(obj, + "{\n" + " \"a\" : 1,\n" + " \"b\" : [ 11, 12 ]\n" + "}"); + + a.push_back(obj); + + add_value(obj, "c", a); + + check_eq(obj, "{\"a\":1,\"b\":[11,12],\"c\":[11,12,{\"a\":1,\"b\":[11,12]}]}"); + check_eq_pretty(obj, + "{\n" + " \"a\" : 1,\n" + " \"b\" : [\n" + " 11,\n" + " 12\n" + " ],\n" + " \"c\" : [\n" + " 11,\n" + " 12,\n" + " {\n" + " \"a\" : 1,\n" + " \"b\" : [\n" + " 11,\n" + " 12\n" + " ]\n" + " }\n" + " ]\n" + "}"); + check_eq_single_line_arrays(obj, + "{\n" + " \"a\" : 1,\n" + " \"b\" : [ 11, 12 ],\n" + " \"c\" : [\n" + " 11,\n" + " 12,\n" + " {\n" + " \"a\" : 1,\n" + " \"b\" : [ 11, 12 ]\n" + " }\n" + " ]\n" + "}"); + } + + void test_escape_char(const char* esc_str_in, const char* esc_str_out, + Output_options options = none) { + Object_type obj; + + const string name_str(string(esc_str_in) + "name"); + + add_value(obj, name_str.c_str(), to_str("value") + to_str(esc_str_in)); + + const string out_str(string("{\"") + esc_str_out + "name\":\"value" + + esc_str_out + "\"}"); + + check_eq(obj, out_str.c_str(), options); + } + + void test_escape_chars() { + test_escape_char("\r", "\\r"); + test_escape_char("\n", "\\n"); + test_escape_char("\t", "\\t"); + test_escape_char("\f", "\\f"); + test_escape_char("\b", "\\b"); + test_escape_char("\"", "\\\""); + test_escape_char("\\", "\\\\"); + test_escape_char("\x01", "\\u0001"); + test_escape_char("\x12", "\\u0012"); + test_escape_char("\x7F", "\\u007F"); + } + + void test_disabling_nonprintable_esc_chars() { + test_escape_char("\t", "\\t", raw_utf8); + test_escape_char("\x01", "\x01", raw_utf8); + test_escape_char("\x01\x12", "\x01\x12", raw_utf8); + } + + void test_to_stream() { + basic_ostringstream os; + + Array_type arr; + + arr.push_back(111); + arr.push_back(222); + + os << hex; // the code should handle this, i.e. output decimal + + write(arr, os); + + assert_eq(os.str(), to_str("[111,222]")); + } + + void test_values() { + check_eq(123, "123"); + check_eq(1.234, "1.234"); + check_eq(to_str("abc"), "\"abc\""); + check_eq(false, "false"); + check_eq(Value_type::null, "null"); + } + + void test_uint64() { + check_eq(Value_type(0), "0"); + check_eq(Value_type(int64_t(0)), "0"); + check_eq(Value_type(uint64_t(0)), "0"); + + check_eq(Value_type(1), "1"); + check_eq(Value_type(int64_t(1)), "1"); + check_eq(Value_type(uint64_t(1)), "1"); + + check_eq(Value_type(-1), "-1"); + check_eq(Value_type(int64_t(-1)), "-1"); + + check_eq(Value_type(max_int64), "9223372036854775807"); + check_eq(Value_type(uint64_t(max_int64)), "9223372036854775807"); + + check_eq(Value_type(max_uint64), "18446744073709551615"); + } + + void test_ios_state_saved() { + basic_ostringstream os; + + os << 0.123456789; + + Array_type arr; + + arr.push_back(0.123456789); + + write(arr, os); + + os << 0.123456789; + + assert_eq(os.str(), to_str("0.123457" + "[0.123456789]" + "0.123457")); + } + + void check_remove_trailing_zeros(const double value, + const String_type& expected_str_with, + const String_type& expected_str_without) { + check_eq(value, expected_str_with, none); + check_eq(value, expected_str_without, remove_trailing_zeros); + } + + void check_remove_trailing_zeros(const double value, const char* expected_str_with, + const char* expected_str_without) { + check_remove_trailing_zeros(value, to_str(expected_str_with), + to_str(expected_str_without)); + } + + void test_remove_trailing_zeros() { +#ifdef WIN32 + const String_type exp = to_str("099"); +#else + const String_type exp = to_str("99"); +#endif + check_remove_trailing_zeros(0.0, "0", "0"); + check_remove_trailing_zeros(1.2, "1.2", "1.2"); + check_remove_trailing_zeros(0.123456789, "0.123456789", "0.123456789"); + check_remove_trailing_zeros(1.2e-99, to_str("1.2e-") + exp, + to_str("1.2e-") + exp); + check_remove_trailing_zeros(1.23456789e99, to_str("1.2345678900000001e+") + exp, + to_str("1.23456789e+") + exp); + } + + void check_precision_of_doubles(unsigned int precision, + const char* expected_result_1, + const char* expected_result_2 = 0) { + Value_type val = 0.1234567890123456789; + assert_eq(write(val, none, precision), to_str(expected_result_1)); + if (!expected_result_2) { + expected_result_2 = expected_result_1; + } + assert_eq(write(val, remove_trailing_zeros, precision), + to_str(expected_result_2)); + } + + void check_precision_of_doubles(const char* expected_result_1, + const char* expected_result_2) { + Value_type val = 0.1234567890123456789; + assert_eq(write(val, none), to_str(expected_result_1)); + assert_eq(write(val, remove_trailing_zeros), to_str(expected_result_2)); + } + + void test_precision_of_doubles() { + // default is 17, or 16 for remove_trailing_zeros flag + check_precision_of_doubles("0.12345678901234568", "0.1234567890123457"); + check_precision_of_doubles(0, "0.12345678901234568", "0.1234567890123457"); + + // specified override is used with or without remove_trailing_zeros flag + check_precision_of_doubles(9, "0.123456789"); + check_precision_of_doubles(6, "0.123457"); + check_precision_of_doubles(1, "0.1"); + } + + void test_multiple_options() { + Value value; + write(value, always_escape_nonascii | pretty_print); + } + + void run_tests() { + test_empty_obj(); + test_obj_with_one_member(); + test_obj_with_two_members(); + test_obj_with_three_members(); + test_obj_with_one_empty_child_obj(); + test_obj_with_one_child_obj(); + test_obj_with_grandchild_obj(); + test_objs_with_bool_pairs(); + test_objs_with_int_pairs(); + test_objs_with_real_pairs(); + test_objs_with_null_pairs(); + test_empty_array(); + test_array_with_one_member(); + test_array_with_two_members(); + test_array_with_n_members(); + test_array_with_one_empty_child_array(); + test_array_with_one_child_array(); + test_array_with_grandchild_array(); + test_array_and_objs(); + test_obj_and_arrays(); + test_escape_chars(); + test_disabling_nonprintable_esc_chars(); + test_to_stream(); + test_values(); + test_uint64(); + test_ios_state_saved(); + test_remove_trailing_zeros(); + test_precision_of_doubles(); + test_multiple_options(); + } +}; + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void test_always_esc_nonascii() { + if (iswprint(L'\x05DE')) { + const wstring s(L"\x05DE\x05E9\x05EA\x05DE\x05E9"); + + wArray arr(1, s); + + const wstring foo = arr[0].get_str(); + + const wstring json_raw = write(arr); + + assert_eq(json_raw, L"[\"" + s + L"\"]"); + + const wstring json_escaped = write(arr, always_escape_nonascii); + + assert_eq(json_escaped, L"[\"\\u05DE\\u05E9\\u05EA\\u05DE\\u05E9\"]"); + } +} + +void test_wide_esc_u(wchar_t c, const wstring& result) { + const wstring s(1, c); + + wArray arr(1, s); + + assert_eq(write(arr), L"[\"\\u" + result + L"\"]"); +} + +void test_wide_esc_u() { + test_wide_esc_u(0xABCD, L"ABCD"); + test_wide_esc_u(0xFFFF, L"FFFF"); +} +#endif + +bool is_printable(char c) { + const wint_t unsigned_c((c >= 0) ? c : 256 + c); + + return iswprint(unsigned_c) != 0; +} + +#ifdef JSON_SPIRIT_VALUE_ENABLED +void test_extended_ascii() { + const string expeced_result(is_printable('\xE4') + ? "[\"\xE4\xF6\xFC\xDF\"]" + : "[\"\\u00E4\\u00F6\\u00FC\\u00DF\"]"); + + assert_eq(write(Array(1, "\xE4\xF6\xFC\xDF")), expeced_result); +} +#endif +} // namespace + +void json5_parser::test_writer() { +#ifdef JSON_SPIRIT_VALUE_ENABLED + Test_runner().run_tests(); + test_extended_ascii(); +#endif +#ifdef JSON_SPIRIT_MVALUE_ENABLED + Test_runner().run_tests(); +#endif +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Test_runner().run_tests(); + test_wide_esc_u(); + test_always_esc_nonascii(); +#endif +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Test_runner().run_tests(); +#endif +} diff --git a/json_test/json5_parser_writer_test.h b/json_test/json5_parser_writer_test.h index 3c9bb77..b1caf5c 100644 --- a/json_test/json5_parser_writer_test.h +++ b/json_test/json5_parser_writer_test.h @@ -1,18 +1,17 @@ -#ifndef JSON_SPIRIT_WRITER_TEST -#define JSON_SPIRIT_WRITER_TEST - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -namespace json5_parser -{ - void test_writer(); -} - -#endif +#ifndef JSON_SPIRIT_WRITER_TEST +#define JSON_SPIRIT_WRITER_TEST + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +namespace json5_parser { +void test_writer(); +} + +#endif diff --git a/json_test/json_test.cpp b/json_test/json_test.cpp index 6d63fbe..ebfb89b 100644 --- a/json_test/json_test.cpp +++ b/json_test/json_test.cpp @@ -1,29 +1,32 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_value_test.h" -#include "json5_parser_writer_test.h" -#include "json5_parser_reader_test.h" -#include "json5_parser_stream_reader_test.h" -#include "json5_parser_utils_test.h" - -#include -#include - -using namespace std; -using namespace json5_parser; - -int main() -{ - test_value(); - test_writer(); - test_reader(); - test_stream_reader(); - test_utils(); - - cout << "all tests passed" << endl << endl; - return 0; -} - +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_reader_test.h" +#include "json5_parser_stream_reader_test.h" +#include "json5_parser_utils_test.h" +#include "json5_parser_value_test.h" +#include "json5_parser_writer_test.h" + +#include +#include + +using namespace std; +using namespace json5_parser; + +int main() { + std::cout << "before test_value()" << std::endl; + test_value(); + std::cout << "before test_writer()" << std::endl; + test_writer(); + std::cout << "before test_reader()" << std::endl; + test_reader(); + std::cout << "before test_stream_reader()" << std::endl; + test_stream_reader(); + std::cout << "before test_utils()" << std::endl; + test_utils(); + + std::cout << "json_test tests all passed" << std::endl; + return 0; +} diff --git a/json_test/utils_test.cpp b/json_test/utils_test.cpp index 73cac15..3ddc599 100644 --- a/json_test/utils_test.cpp +++ b/json_test/utils_test.cpp @@ -1,15 +1,14 @@ -// Copyright John W. Wilkinson 2011 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "utils_test.h" - -void assert_eq( const double d1, const double d2, const double abs_error ) -{ - const double err = fabs( d1 - d2 ); - - if( err <= abs_error ) return; - - assert( false ); -} +// Copyright John W. Wilkinson 2011 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "utils_test.h" + +void assert_eq(const double d1, const double d2, const double abs_error) { + const double err = fabs(d1 - d2); + + if (err <= abs_error) return; + + assert(false); +} diff --git a/json_test/utils_test.h b/json_test/utils_test.h index 9f65731..e2364c0 100644 --- a/json_test/utils_test.h +++ b/json_test/utils_test.h @@ -1,36 +1,34 @@ -#ifndef JSON_SPIRIT_TEST_UTILS -#define JSON_SPIRIT_TEST_UTILS - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include -#include - -// these functions allow you to inspect the values that caused a test to fail - -template< class T1, class T2 > -void assert_eq( const T1& t1, const T2& t2 ) -{ - if( t1 == t2 ) return; - - assert( false ); -} - -template< class T1, class T2 > -void assert_neq( const T1& t1, const T2& t2 ) -{ - if( !(t1 == t2) ) return; - - assert( false ); -} - -void assert_eq( const double d1, const double d2, const double abs_error ); - -#endif +#ifndef JSON_SPIRIT_TEST_UTILS +#define JSON_SPIRIT_TEST_UTILS + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include +#include + +// these functions allow you to inspect the values that caused a test to fail + +template +void assert_eq(const T1& t1, const T2& t2) { + if (t1 == t2) return; + + assert(false); +} + +template +void assert_neq(const T1& t1, const T2& t2) { + if (!(t1 == t2)) return; + + assert(false); +} + +void assert_eq(const double d1, const double d2, const double abs_error); + +#endif diff --git a/wscript b/wscript index 8017a38..cc52cae 100644 --- a/wscript +++ b/wscript @@ -8,7 +8,7 @@ def configure(conf): conf.check_boost(lib='system thread') def build(bld): - default_flags=['-Wall', '-Wextra', '-Ofast'] + default_flags=['-Wall', '-Wextra', '-O3'] # default_flags=['-Wall', '-Wextra', '-g'] use_packages=['BOOST'] includes=['json5_parser']