boost/json/detail/parse_into.hpp
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_DETAIL_PARSE_INTO_HPP
#define BOOST_JSON_DETAIL_PARSE_INTO_HPP
#include <boost/json/detail/config.hpp>
#include <boost/json/error.hpp>
#include <boost/json/conversion.hpp>
#include <boost/describe/enum_from_string.hpp>
#include <vector>
/*
* This file contains the majority of parse_into functionality, specifically
* the implementation of dedicated handlers for different generic categories of
* types.
*
* At the core of parse_into is the specialisation basic_parser<
* detail::into_handler<T> >. detail::into_handler<T> is a handler for
* basic_parser. It directly handles events on_comment_part and on_comment (by
* ignoring them), on_document_begin (by enabling the nested dedicated
* handler), and on_document_end (by disabling the nested handler).
*
* Every other event is handled by the nested handler, which has the type
* get_handler< T, into_handler<T> >. The second parameter is the parent
* handler (in this case, it's the top handler, into_handler<T>). The type is
* actually an alias to class template converting_handler, which has a separate
* specialisation for every conversion category from the list of generic
* conversion categories (e.g. sequence_conversion_tag, tuple_conversion_tag,
* etc.) Instantiations of the template store a pointer to the parent handler
* and a pointer to the value T.
*
* The nested handler handles specific parser events by setting error_code to
* an appropriate value, if it receives an event it isn't supposed to handle
* (e.g. a number handler getting an on_string event), and also updates the
* value when appropriate. Note that they never need to handle on_comment_part,
* on_comment, on_document_begin, and on_document_end events, as those are
* always handled by the top handler into_handler<T>.
*
* When the nested handler receives an event that completes the current value,
* it is supposed to call its parent's signal_value member function. This is
* necessary for correct handling of composite types (e.g. sequences).
*
* Finally, nested handlers should always call parent's signal_end member
* function if they don't handle on_array_end themselves. This is necessary
* to correctly handle nested composites (e.g. sequences inside sequences).
* signal_end can return false and set error state when the containing parser
* requires more elements.
*
* converting_handler instantiations for composite categories of types have
* their own nested handlers, to which they themselves delegate events. For
* complex types you will get a tree of handlers with into_handler<T> as the
* root and handlers for scalars as leaves.
*
* To reiterate, only into_handler has to handle on_comment_part, on_comment,
* on_document_begin, and on_document_end; only handlers for composites and
* into_handler has to provide signal_value and signal_end; all handlers
* except for into_handler have to call their parent's signal_end from
* their on_array_begin, if they don't handle it themselves; once a handler
* receives an event that finishes its current value, it should call its
* parent's signal_value.
*/
namespace boost {
namespace json {
namespace detail {
template< class Impl, class T, class Parent >
class converting_handler;
// get_handler
template< class V, class P >
using get_handler = converting_handler< generic_conversion_category<V>, V, P >;
template<error E> class handler_error_base
{
public:
handler_error_base() = default;
handler_error_base( handler_error_base const& ) = delete;
handler_error_base& operator=( handler_error_base const& ) = delete;
public:
bool on_object_begin( system::error_code& ec ) { BOOST_JSON_FAIL( ec, E ); return false; }
bool on_array_begin( system::error_code& ec ) { BOOST_JSON_FAIL( ec, E ); return false; }
bool on_array_end( system::error_code& ec ) { BOOST_JSON_FAIL( ec, E ); return false; }
bool on_string_part( system::error_code& ec, string_view ) { BOOST_JSON_FAIL( ec, E ); return false; }
bool on_string( system::error_code& ec, string_view ) { BOOST_JSON_FAIL( ec, E ); return false; }
bool on_number_part( system::error_code& ec ) { BOOST_JSON_FAIL( ec, E ); return false; }
bool on_int64( system::error_code& ec, std::int64_t ) { BOOST_JSON_FAIL( ec, E ); return false; }
bool on_uint64( system::error_code& ec, std::uint64_t ) { BOOST_JSON_FAIL( ec, E ); return false; }
bool on_double( system::error_code& ec, double ) { BOOST_JSON_FAIL( ec, E ); return false; }
bool on_bool( system::error_code& ec, bool ) { BOOST_JSON_FAIL( ec, E ); return false; }
bool on_null( system::error_code& ec ) { BOOST_JSON_FAIL( ec, E ); return false; }
// LCOV_EXCL_START
// parses that can't handle this would fail at on_object_begin
bool on_object_end( system::error_code& ) { BOOST_ASSERT( false ); return false; }
bool on_key_part( system::error_code& ec, string_view ) { BOOST_JSON_FAIL( ec, E ); return false; }
bool on_key( system::error_code& ec, string_view ) { BOOST_JSON_FAIL( ec, E ); return false; }
// LCOV_EXCL_START
};
template< class P, error E >
class scalar_handler
: public handler_error_base<E>
{
protected:
P* parent_;
public:
scalar_handler(scalar_handler const&) = delete;
scalar_handler& operator=(scalar_handler const&) = delete;
scalar_handler(P* p): parent_( p )
{}
bool on_array_end( system::error_code& ec )
{
return parent_->signal_end(ec);
}
};
template< class D, class V, class P, error E >
class composite_handler
{
protected:
using inner_handler_type = get_handler<V, D>;
P* parent_;
#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
V next_value_ = {};
inner_handler_type inner_;
bool inner_active_ = false;
public:
composite_handler( composite_handler const& ) = delete;
composite_handler& operator=( composite_handler const& ) = delete;
composite_handler( P* p )
: parent_(p), inner_( &next_value_, static_cast<D*>(this) )
{}
#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
# pragma GCC diagnostic pop
#endif
bool signal_end(system::error_code&)
{
inner_active_ = false;
parent_->signal_value();
return true;
}
#define BOOST_JSON_INVOKE_INNER(f) \
if( !inner_active_ ) { \
BOOST_JSON_FAIL(ec, E); \
return false; \
} \
else \
return inner_.f
bool on_object_begin( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_object_begin(ec) );
}
bool on_object_end( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_object_end(ec) );
}
bool on_array_begin( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_array_begin(ec) );
}
bool on_array_end( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_array_end(ec) );
}
bool on_key_part( system::error_code& ec, string_view sv )
{
BOOST_JSON_INVOKE_INNER( on_key_part(ec, sv) );
}
bool on_key( system::error_code& ec, string_view sv )
{
BOOST_JSON_INVOKE_INNER( on_key(ec, sv) );
}
bool on_string_part( system::error_code& ec, string_view sv )
{
BOOST_JSON_INVOKE_INNER( on_string_part(ec, sv) );
}
bool on_string( system::error_code& ec, string_view sv )
{
BOOST_JSON_INVOKE_INNER( on_string(ec, sv) );
}
bool on_number_part( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_number_part(ec) );
}
bool on_int64( system::error_code& ec, std::int64_t v )
{
BOOST_JSON_INVOKE_INNER( on_int64(ec, v) );
}
bool on_uint64( system::error_code& ec, std::uint64_t v )
{
BOOST_JSON_INVOKE_INNER( on_uint64(ec, v) );
}
bool on_double( system::error_code& ec, double v )
{
BOOST_JSON_INVOKE_INNER( on_double(ec, v) );
}
bool on_bool( system::error_code& ec, bool v )
{
BOOST_JSON_INVOKE_INNER( on_bool(ec, v) );
}
bool on_null( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_null(ec) );
}
#undef BOOST_JSON_INVOKE_INNER
};
// integral handler
template<class V,
typename std::enable_if<std::is_signed<V>::value, int>::type = 0>
bool integral_in_range( std::int64_t v )
{
return v >= (std::numeric_limits<V>::min)() && v <= (std::numeric_limits<V>::max)();
}
template<class V,
typename std::enable_if<!std::is_signed<V>::value, int>::type = 0>
bool integral_in_range( std::int64_t v )
{
return v >= 0 && static_cast<std::uint64_t>( v ) <= (std::numeric_limits<V>::max)();
}
template<class V>
bool integral_in_range( std::uint64_t v )
{
return v <= static_cast<typename std::make_unsigned<V>::type>( (std::numeric_limits<V>::max)() );
}
template< class V, class P >
class converting_handler<integral_conversion_tag, V, P>
: public scalar_handler<P, error::not_integer>
{
private:
V* value_;
public:
converting_handler( V* v, P* p )
: converting_handler::scalar_handler(p)
, value_(v)
{}
bool on_number_part( system::error_code& )
{
return true;
}
bool on_int64( system::error_code& ec, std::int64_t v )
{
if( !integral_in_range<V>( v ) )
{
BOOST_JSON_FAIL( ec, error::not_exact );
return false;
}
*value_ = static_cast<V>( v );
this->parent_->signal_value();
return true;
}
bool on_uint64( system::error_code& ec, std::uint64_t v )
{
if( !integral_in_range<V>( v ) )
{
BOOST_JSON_FAIL( ec, error::not_exact );
return false;
}
*value_ = static_cast<V>( v );
this->parent_->signal_value();
return true;
}
};
// floating point handler
template< class V, class P>
class converting_handler<floating_point_conversion_tag, V, P>
: public scalar_handler<P, error::not_double>
{
private:
V* value_;
public:
converting_handler( V* v, P* p )
: converting_handler::scalar_handler(p)
, value_(v)
{}
bool on_number_part( system::error_code& )
{
return true;
}
bool on_int64( system::error_code&, std::int64_t v )
{
*value_ = static_cast<V>( v );
this->parent_->signal_value();
return true;
}
bool on_uint64( system::error_code&, std::uint64_t v )
{
*value_ = static_cast<V>( v );
this->parent_->signal_value();
return true;
}
bool on_double( system::error_code&, double v )
{
*value_ = static_cast<V>( v );
this->parent_->signal_value();
return true;
}
};
// string handler
template< class V, class P >
class converting_handler<string_like_conversion_tag, V, P>
: public scalar_handler<P, error::not_string>
{
private:
V* value_;
bool cleared_ = false;
public:
converting_handler( V* v, P* p )
: converting_handler::scalar_handler(p)
, value_(v)
{}
bool on_string_part( system::error_code&, string_view sv )
{
if( !cleared_ )
{
cleared_ = true;
value_->clear();
}
value_->append( sv.begin(), sv.end() );
return true;
}
bool on_string( system::error_code&, string_view sv )
{
if( !cleared_ )
value_->clear();
else
cleared_ = false;
value_->append( sv.begin(), sv.end() );
this->parent_->signal_value();
return true;
}
};
// bool handler
template< class V, class P >
class converting_handler<bool_conversion_tag, V, P>
: public scalar_handler<P, error::not_bool>
{
private:
V* value_;
public:
converting_handler( V* v, P* p )
: converting_handler::scalar_handler(p)
, value_(v)
{}
bool on_bool( system::error_code&, bool v )
{
*value_ = v;
this->parent_->signal_value();
return true;
}
};
// null handler
template< class V, class P >
class converting_handler<null_like_conversion_tag, V, P>
: public scalar_handler<P, error::not_null>
{
private:
V* value_;
public:
converting_handler( V* v, P* p )
: converting_handler::scalar_handler(p)
, value_(v)
{}
bool on_null( system::error_code& )
{
*value_ = {};
this->parent_->signal_value();
return true;
}
};
// described enum handler
template< class V, class P >
class converting_handler<described_enum_conversion_tag, V, P>
: public scalar_handler<P, error::not_string>
{
#ifndef BOOST_DESCRIBE_CXX14
static_assert(
sizeof(V) == 0, "Enum support for parse_into requires C++14" );
#else
private:
V* value_;
std::string name_;
public:
converting_handler( V* v, P* p )
: converting_handler::scalar_handler(p)
, value_(v)
{}
bool on_string_part( system::error_code&, string_view sv )
{
name_.append( sv.begin(), sv.end() );
return true;
}
bool on_string( system::error_code& ec, string_view sv )
{
string_view name = sv;
if( !name_.empty() )
{
name_.append( sv.begin(), sv.end() );
name = name_;
}
if( !describe::enum_from_string(name, *value_) )
{
BOOST_JSON_FAIL(ec, error::unknown_name);
return false;
}
this->parent_->signal_value();
return true;
}
#endif // BOOST_DESCRIBE_CXX14
};
template< class V, class P >
class converting_handler<no_conversion_tag, V, P>
{
static_assert( sizeof(V) == 0, "This type is not supported" );
};
// sequence handler
template< class It >
bool check_inserter( It l, It r )
{
return l == r;
}
template< class It1, class It2 >
std::true_type check_inserter( It1, It2 )
{
return {};
}
template<class T>
void
clear_container(
T&,
mp11::mp_int<2>)
{
}
template<class T>
void
clear_container(
T& target,
mp11::mp_int<1>)
{
target.clear();
}
template<class T>
void
clear_container(
T& target,
mp11::mp_int<0>)
{
target.clear();
}
template< class V, class P >
class converting_handler<sequence_conversion_tag, V, P>
: public composite_handler<
converting_handler<sequence_conversion_tag, V, P>,
detail::value_type<V>,
P,
error::not_array>
{
private:
V* value_;
using Inserter = decltype(
detail::inserter(*value_, inserter_implementation<V>()) );
Inserter inserter;
public:
converting_handler( V* v, P* p )
: converting_handler::composite_handler(p)
, value_(v)
, inserter( detail::inserter(*value_, inserter_implementation<V>()) )
{}
void signal_value()
{
*inserter++ = std::move(this->next_value_);
#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
this->next_value_ = {};
#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
# pragma GCC diagnostic pop
#endif
}
bool signal_end(system::error_code& ec)
{
if( !check_inserter( inserter, value_->end() ) )
{
BOOST_JSON_FAIL( ec, error::size_mismatch );
return false;
}
inserter = detail::inserter(*value_, inserter_implementation<V>());
return converting_handler::composite_handler::signal_end(ec);
}
bool on_array_begin( system::error_code& ec )
{
if( this->inner_active_ )
return this->inner_.on_array_begin( ec );
this->inner_active_ = true;
clear_container( *value_, inserter_implementation<V>() );
return true;
}
bool on_array_end( system::error_code& ec )
{
if( this->inner_active_ )
return this->inner_.on_array_end( ec );
return this->parent_->signal_end(ec);
}
};
// map handler
template< class V, class P >
class converting_handler<map_like_conversion_tag, V, P>
: public composite_handler<
converting_handler<map_like_conversion_tag, V, P>,
detail::mapped_type<V>,
P,
error::not_object>
{
private:
V* value_;
std::string key_;
public:
converting_handler( V* v, P* p )
: converting_handler::composite_handler(p), value_(v)
{}
void signal_value()
{
value_->emplace( std::move(key_), std::move(this->next_value_) );
key_ = {};
this->next_value_ = {};
this->inner_active_ = false;
}
bool on_object_begin( system::error_code& ec )
{
if( this->inner_active_ )
return this->inner_.on_object_begin(ec);
clear_container( *value_, inserter_implementation<V>() );
return true;
}
bool on_object_end( system::error_code& ec )
{
if( this->inner_active_ )
return this->inner_.on_object_end(ec);
this->parent_->signal_value();
return true;
}
bool on_array_end( system::error_code& ec )
{
if( this->inner_active_ )
return this->inner_.on_array_end(ec);
return this->parent_->signal_end(ec);
}
bool on_key_part( system::error_code& ec, string_view sv )
{
if( this->inner_active_ )
return this->inner_.on_key_part(ec, sv);
key_.append( sv.data(), sv.size() );
return true;
}
bool on_key( system::error_code& ec, string_view sv )
{
if( this->inner_active_ )
return this->inner_.on_key(ec, sv);
key_.append( sv.data(), sv.size() );
this->inner_active_ = true;
return true;
}
};
// tuple handler
template<std::size_t I, class T>
struct handler_tuple_element
{
template< class... Args >
handler_tuple_element( Args&& ... args )
: t_( static_cast<Args&&>(args)... )
{}
T t_;
};
template<std::size_t I, class T>
T&
get( handler_tuple_element<I, T>& e )
{
return e.t_;
}
template<
class P,
class LV,
class S = mp11::make_index_sequence<mp11::mp_size<LV>::value> >
struct handler_tuple;
template< class P, template<class...> class L, class... V, std::size_t... I >
struct handler_tuple< P, L<V...>, mp11::index_sequence<I...> >
: handler_tuple_element< I, get_handler<V, P> >
...
{
handler_tuple( handler_tuple const& ) = delete;
handler_tuple& operator=( handler_tuple const& ) = delete;
template< class Access, class T >
handler_tuple( Access access, T* pv, P* pp )
: handler_tuple_element< I, get_handler<V, P> >(
access( pv, mp11::mp_int<I>() ),
pp )
...
{ }
};
#if defined(BOOST_MSVC) && BOOST_MSVC < 1910
template< class T >
struct tuple_element_list_impl
{
template< class I >
using tuple_element_helper = tuple_element_t<I::value, T>;
using type = mp11::mp_transform<
tuple_element_helper,
mp11::mp_iota< std::tuple_size<T> > >;
};
template< class T >
using tuple_element_list = typename tuple_element_list_impl<T>::type;
#else
template< class I, class T >
using tuple_element_helper = tuple_element_t<I::value, T>;
template< class T >
using tuple_element_list = mp11::mp_transform_q<
mp11::mp_bind_back< tuple_element_helper, T>,
mp11::mp_iota< std::tuple_size<T> > >;
#endif
template< class Op, class... Args>
struct handler_op_invoker
{
public:
std::tuple<Args&...> args;
template< class Handler >
bool
operator()( Handler& handler ) const
{
return (*this)( handler, mp11::index_sequence_for<Args...>() );
}
private:
template< class Handler, std::size_t... I >
bool
operator()( Handler& handler, mp11::index_sequence<I...> ) const
{
return Op()( handler, std::get<I>(args)... );
}
};
template< class Handlers, class F >
struct tuple_handler_op_invoker
{
Handlers& handlers;
F fn;
template< class I >
bool
operator()( I ) const
{
return fn( get<I::value>(handlers) );
}
};
struct tuple_accessor
{
template< class T, class I >
auto operator()( T* t, I ) const -> tuple_element_t<I::value, T>*
{
using std::get;
return &get<I::value>(*t);
}
};
template< class T, class P >
class converting_handler<tuple_conversion_tag, T, P>
{
private:
T* value_;
P* parent_;
handler_tuple< converting_handler, tuple_element_list<T> > handlers_;
int inner_active_ = -1;
public:
converting_handler( converting_handler const& ) = delete;
converting_handler& operator=( converting_handler const& ) = delete;
converting_handler( T* v, P* p )
: value_(v) , parent_(p) , handlers_(tuple_accessor(), v, this)
{}
void signal_value()
{
++inner_active_;
}
bool signal_end(system::error_code& ec)
{
constexpr int N = std::tuple_size<T>::value;
if( inner_active_ < N )
{
BOOST_JSON_FAIL( ec, error::size_mismatch );
return true;
}
inner_active_ = -1;
parent_->signal_value();
return true;
}
#define BOOST_JSON_HANDLE_EVENT(fn) \
struct do_ ## fn \
{ \
template< class H, class... Args > \
bool operator()( H& h, Args& ... args ) const \
{ \
return h. fn (args...); \
} \
}; \
\
template< class... Args > \
bool fn( system::error_code& ec, Args&& ... args ) \
{ \
if( inner_active_ < 0 ) \
{ \
BOOST_JSON_FAIL( ec, error::not_array ); \
return false; \
} \
constexpr int N = std::tuple_size<T>::value; \
if( inner_active_ >= N ) \
{ \
BOOST_JSON_FAIL( ec, error::size_mismatch ); \
return false; \
} \
using F = handler_op_invoker< do_ ## fn, system::error_code, Args...>; \
using H = decltype(handlers_); \
return mp11::mp_with_index<N>( \
inner_active_, \
tuple_handler_op_invoker<H, F>{ \
handlers_, \
F{ std::forward_as_tuple(ec, args...) } } ); \
}
BOOST_JSON_HANDLE_EVENT( on_object_begin )
BOOST_JSON_HANDLE_EVENT( on_object_end )
struct do_on_array_begin
{
handler_tuple< converting_handler, tuple_element_list<T> >& handlers;
system::error_code& ec;
template< class I >
bool operator()( I ) const
{
return get<I::value>(handlers).on_array_begin(ec);
}
};
bool on_array_begin( system::error_code& ec )
{
if( inner_active_ < 0 )
{
inner_active_ = 0;
return true;
}
constexpr int N = std::tuple_size<T>::value;
if( inner_active_ >= N )
{
inner_active_ = 0;
return true;
}
return mp11::mp_with_index<N>(
inner_active_, do_on_array_begin{handlers_, ec} );
}
struct do_on_array_end
{
handler_tuple< converting_handler, tuple_element_list<T> >& handlers;
system::error_code& ec;
template< class I >
bool operator()( I ) const
{
return get<I::value>(handlers).on_array_end(ec);
}
};
bool on_array_end( system::error_code& ec )
{
if( inner_active_ < 0 )
return parent_->signal_end(ec);
constexpr int N = std::tuple_size<T>::value;
if( inner_active_ >= N )
return signal_end(ec);
return mp11::mp_with_index<N>(
inner_active_, do_on_array_end{handlers_, ec} );
}
BOOST_JSON_HANDLE_EVENT( on_key_part )
BOOST_JSON_HANDLE_EVENT( on_key )
BOOST_JSON_HANDLE_EVENT( on_string_part )
BOOST_JSON_HANDLE_EVENT( on_string )
BOOST_JSON_HANDLE_EVENT( on_number_part )
BOOST_JSON_HANDLE_EVENT( on_int64 )
BOOST_JSON_HANDLE_EVENT( on_uint64 )
BOOST_JSON_HANDLE_EVENT( on_double )
BOOST_JSON_HANDLE_EVENT( on_bool )
BOOST_JSON_HANDLE_EVENT( on_null )
#undef BOOST_JSON_HANDLE_EVENT
};
// described struct handler
#if defined(BOOST_MSVC) && BOOST_MSVC < 1910
template< class T >
struct struct_element_list_impl
{
template< class D >
using helper = described_member_t<T, D>;
using type = mp11::mp_transform< helper, described_members<T> >;
};
template< class T >
using struct_element_list = typename struct_element_list_impl<T>::type;
#else
template< class T >
using struct_element_list = mp11::mp_transform_q<
mp11::mp_bind_front< described_member_t, T >, described_members<T> >;
#endif
struct struct_accessor
{
template< class T, class I >
auto operator()( T* t, I ) const
-> described_member_t<T, mp11::mp_at< described_members<T>, I> >*
{
using Ds = described_members<T>;
using D = mp11::mp_at<Ds, I>;
return &(t->*D::pointer);
}
};
template< class F >
struct struct_key_searcher
{
F fn;
template< class D >
void
operator()( D ) const
{
fn( D::name ) ;
}
};
template<class V, class P>
class converting_handler<described_class_conversion_tag, V, P>
{
#if !defined(BOOST_DESCRIBE_CXX14)
static_assert(
sizeof(V) == 0, "Struct support for parse_into requires C++14" );
#else
private:
V* value_;
P* parent_;
std::string key_;
using Dm = described_members<V>;
handler_tuple< converting_handler, struct_element_list<V> > handlers_;
int inner_active_ = -1;
std::size_t activated_ = 0;
public:
converting_handler( converting_handler const& ) = delete;
converting_handler& operator=( converting_handler const& ) = delete;
converting_handler( V* v, P* p )
: value_(v), parent_(p), handlers_(struct_accessor(), v, this)
{}
struct is_optional_checker
{
template< class I >
bool operator()( I ) const noexcept
{
using L = struct_element_list<V>;
using T = mp11::mp_at<L, I>;
return !is_optional_like<T>::value;
}
};
void signal_value()
{
BOOST_ASSERT( inner_active_ >= 0 );
bool required_member = mp11::mp_with_index< mp11::mp_size<Dm> >(
inner_active_,
is_optional_checker{});
if( required_member )
++activated_;
key_ = {};
inner_active_ = -1;
}
bool signal_end(system::error_code&)
{
key_ = {};
inner_active_ = -1;
parent_->signal_value();
return true;
}
#define BOOST_JSON_INVOKE_INNER(fn) \
if( inner_active_ < 0 ) \
{ \
BOOST_JSON_FAIL( ec, error::not_object ); \
return false; \
} \
auto f = [&](auto& handler) { return handler.fn ; }; \
using F = decltype(f); \
using H = decltype(handlers_); \
return mp11::mp_with_index< mp11::mp_size<Dm> >( \
inner_active_, \
tuple_handler_op_invoker<H, F>{handlers_, f} );
bool on_object_begin( system::error_code& ec )
{
if( inner_active_ < 0 )
return true;
BOOST_JSON_INVOKE_INNER( on_object_begin(ec) );
}
bool on_object_end( system::error_code& ec )
{
if( inner_active_ < 0 )
{
using L = struct_element_list<V>;
using C = mp11::mp_count_if<L, is_optional_like>;
constexpr int N = mp11::mp_size<L>::value - C::value;
if( activated_ < N )
{
BOOST_JSON_FAIL( ec, error::size_mismatch );
return false;
}
parent_->signal_value();
return true;
}
BOOST_JSON_INVOKE_INNER( on_object_end(ec) );
}
bool on_array_begin( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_array_begin(ec) );
}
bool on_array_end( system::error_code& ec )
{
if( inner_active_ < 0 )
return parent_->signal_end(ec);
BOOST_JSON_INVOKE_INNER( on_array_end(ec) );
}
bool on_key_part( system::error_code& ec, string_view sv )
{
if( inner_active_ < 0 )
{
key_.append( sv.data(), sv.size() );
return true;
}
BOOST_JSON_INVOKE_INNER( on_key_part(ec, sv) );
}
bool on_key( system::error_code& ec, string_view sv )
{
if( inner_active_ >= 0 )
{
BOOST_JSON_INVOKE_INNER( on_key(ec, sv) );
}
string_view key = sv;
if( !key_.empty() )
{
key_.append( sv.data(), sv.size() );
key = key_;
}
int i = 0;
auto f = [&](char const* name)
{
if( key == name )
inner_active_ = i;
++i;
};
mp11::mp_for_each<Dm>(
struct_key_searcher<decltype(f)>{f} );
if( inner_active_ < 0 )
{
BOOST_JSON_FAIL(ec, error::unknown_name);
return false;
}
return true;
}
bool on_string_part( system::error_code& ec, string_view sv )
{
BOOST_JSON_INVOKE_INNER( on_string_part(ec, sv) );
}
bool on_string( system::error_code& ec, string_view sv )
{
BOOST_JSON_INVOKE_INNER( on_string(ec, sv) );
}
bool on_number_part( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_number_part(ec) );
}
bool on_int64( system::error_code& ec, std::int64_t v )
{
BOOST_JSON_INVOKE_INNER( on_int64(ec, v) );
}
bool on_uint64( system::error_code& ec, std::uint64_t v )
{
BOOST_JSON_INVOKE_INNER( on_uint64(ec, v) );
}
bool on_double( system::error_code& ec, double v )
{
BOOST_JSON_INVOKE_INNER( on_double(ec, v) );
}
bool on_bool( system::error_code& ec, bool v )
{
BOOST_JSON_INVOKE_INNER( on_bool(ec, v) );
}
bool on_null( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_null(ec) );
}
#undef BOOST_JSON_INVOKE_INNER
#endif
};
// variant handler
struct object_begin_handler_event
{ };
struct object_end_handler_event
{ };
struct array_begin_handler_event
{ };
struct array_end_handler_event
{ };
struct key_handler_event
{
std::string value;
};
struct string_handler_event
{
std::string value;
};
struct int64_handler_event
{
std::int64_t value;
};
struct uint64_handler_event
{
std::uint64_t value;
};
struct double_handler_event
{
double value;
};
struct bool_handler_event
{
bool value;
};
struct null_handler_event
{ };
using parse_event = variant2::variant<
object_begin_handler_event,
object_end_handler_event,
array_begin_handler_event,
array_end_handler_event,
key_handler_event,
string_handler_event,
int64_handler_event,
uint64_handler_event,
double_handler_event,
bool_handler_event,
null_handler_event>;
template< class H >
struct event_visitor
{
H& handler;
system::error_code& ec;
bool
operator()(object_begin_handler_event&) const
{
return handler.on_object_begin(ec);
}
bool
operator()(object_end_handler_event&) const
{
return handler.on_object_end(ec);
}
bool
operator()(array_begin_handler_event&) const
{
return handler.on_array_begin(ec);
}
bool
operator()(array_end_handler_event&) const
{
return handler.on_array_end(ec);
}
bool
operator()(key_handler_event& ev) const
{
return handler.on_key(ec, ev.value);
}
bool
operator()(string_handler_event& ev) const
{
return handler.on_string(ec, ev.value);
}
bool
operator()(int64_handler_event& ev) const
{
return handler.on_int64(ec, ev.value);
}
bool
operator()(uint64_handler_event& ev) const
{
return handler.on_uint64(ec, ev.value);
}
bool
operator()(double_handler_event& ev) const
{
return handler.on_double(ec, ev.value);
}
bool
operator()(bool_handler_event& ev) const
{
return handler.on_bool(ec, ev.value);
}
bool
operator()(null_handler_event&) const
{
return handler.on_null(ec);
}
};
// L<T...> -> variant< monostate, get_handler<T, P>... >
template< class P, class L >
using inner_handler_variant = mp11::mp_push_front<
mp11::mp_transform_q<
mp11::mp_bind_back<get_handler, P>,
mp11::mp_apply<variant2::variant, L>>,
variant2::monostate>;
template< class T, class P >
class converting_handler<variant_conversion_tag, T, P>
{
private:
using variant_size = mp11::mp_size<T>;
T* value_;
P* parent_;
std::string string_;
std::vector< parse_event > events_;
inner_handler_variant<converting_handler, T> inner_;
int inner_active_ = -1;
public:
converting_handler( converting_handler const& ) = delete;
converting_handler& operator=( converting_handler const& ) = delete;
converting_handler( T* v, P* p )
: value_( v )
, parent_( p )
{}
void signal_value()
{
inner_.template emplace<0>();
inner_active_ = -1;
events_.clear();
parent_->signal_value();
}
bool signal_end(system::error_code& ec)
{
return parent_->signal_end(ec);
}
struct alternative_selector
{
converting_handler* self;
template< class I >
void
operator()( I ) const
{
using V = mp11::mp_at<T, I>;
auto& v = self->value_->template emplace<I::value>( V{} );
self->inner_.template emplace<I::value + 1>(&v, self);
}
};
void
next_alternative()
{
if( ++inner_active_ >= static_cast<int>(variant_size::value) )
return;
mp11::mp_with_index< variant_size::value >(
inner_active_, alternative_selector{this} );
}
struct event_processor
{
converting_handler* self;
system::error_code& ec;
parse_event& event;
template< class I >
bool operator()( I ) const
{
auto& handler = variant2::get<I::value + 1>(self->inner_);
using Handler = remove_cvref<decltype(handler)>;
return variant2::visit(
event_visitor<Handler>{handler, ec}, event );
}
};
bool process_events(system::error_code& ec)
{
constexpr std::size_t N = variant_size::value;
// should be pointers not iterators, otherwise MSVC crashes
auto const last = events_.data() + events_.size();
auto first = last - 1;
bool ok = false;
if( inner_active_ < 0 )
next_alternative();
do
{
if( static_cast<std::size_t>(inner_active_) >= N )
{
BOOST_JSON_FAIL( ec, error::exhausted_variants );
return false;
}
for ( ; first != last; ++first )
{
ok = mp11::mp_with_index< N >(
inner_active_, event_processor{this, ec, *first} );
if( !ok )
{
first = events_.data();
next_alternative();
ec.clear();
break;
}
}
}
while( !ok );
return true;
}
#define BOOST_JSON_INVOKE_INNER(ev, ec) \
events_.emplace_back( ev ); \
return process_events(ec);
bool on_object_begin( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( object_begin_handler_event{}, ec );
}
bool on_object_end( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( object_end_handler_event{}, ec );
}
bool on_array_begin( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( array_begin_handler_event{}, ec );
}
bool on_array_end( system::error_code& ec )
{
if( !inner_active_ )
return signal_end(ec);
BOOST_JSON_INVOKE_INNER( array_end_handler_event{}, ec );
}
bool on_key_part( system::error_code&, string_view sv )
{
string_.append(sv);
return true;
}
bool on_key( system::error_code& ec, string_view sv )
{
string_.append(sv);
BOOST_JSON_INVOKE_INNER( key_handler_event{ std::move(string_) }, ec );
}
bool on_string_part( system::error_code&, string_view sv )
{
string_.append(sv);
return true;
}
bool on_string( system::error_code& ec, string_view sv )
{
string_.append(sv);
BOOST_JSON_INVOKE_INNER(
string_handler_event{ std::move(string_) }, ec );
}
bool on_number_part( system::error_code& )
{
return true;
}
bool on_int64( system::error_code& ec, std::int64_t v )
{
BOOST_JSON_INVOKE_INNER( int64_handler_event{v}, ec );
}
bool on_uint64( system::error_code& ec, std::uint64_t v )
{
BOOST_JSON_INVOKE_INNER( uint64_handler_event{v}, ec );
}
bool on_double( system::error_code& ec, double v )
{
BOOST_JSON_INVOKE_INNER( double_handler_event{v}, ec );
}
bool on_bool( system::error_code& ec, bool v )
{
BOOST_JSON_INVOKE_INNER( bool_handler_event{v}, ec );
}
bool on_null( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( null_handler_event{}, ec );
}
#undef BOOST_JSON_INVOKE_INNER
};
// optional handler
template<class V, class P>
class converting_handler<optional_conversion_tag, V, P>
{
private:
using inner_type = value_result_type<V>;
using inner_handler_type = get_handler<inner_type, converting_handler>;
V* value_;
P* parent_;
inner_type inner_value_ = {};
inner_handler_type inner_;
bool inner_active_ = false;
public:
converting_handler( converting_handler const& ) = delete;
converting_handler& operator=( converting_handler const& ) = delete;
converting_handler( V* v, P* p )
: value_(v), parent_(p), inner_(&inner_value_, this)
{}
void signal_value()
{
*value_ = std::move(inner_value_);
inner_active_ = false;
parent_->signal_value();
}
bool signal_end(system::error_code& ec)
{
return parent_->signal_end(ec);
}
#define BOOST_JSON_INVOKE_INNER(fn) \
if( !inner_active_ ) \
inner_active_ = true; \
return inner_.fn;
bool on_object_begin( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_object_begin(ec) );
}
bool on_object_end( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_object_end(ec) );
}
bool on_array_begin( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_array_begin(ec) );
}
bool on_array_end( system::error_code& ec )
{
if( !inner_active_ )
return signal_end(ec);
BOOST_JSON_INVOKE_INNER( on_array_end(ec) );
}
bool on_key_part( system::error_code& ec, string_view sv )
{
BOOST_JSON_INVOKE_INNER( on_key_part(ec, sv) );
}
bool on_key( system::error_code& ec, string_view sv )
{
BOOST_JSON_INVOKE_INNER( on_key(ec, sv) );
}
bool on_string_part( system::error_code& ec, string_view sv )
{
BOOST_JSON_INVOKE_INNER( on_string_part(ec, sv) );
}
bool on_string( system::error_code& ec, string_view sv )
{
BOOST_JSON_INVOKE_INNER( on_string(ec, sv) );
}
bool on_number_part( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_number_part(ec) );
}
bool on_int64( system::error_code& ec, std::int64_t v )
{
BOOST_JSON_INVOKE_INNER( on_int64(ec, v) );
}
bool on_uint64( system::error_code& ec, std::uint64_t v )
{
BOOST_JSON_INVOKE_INNER( on_uint64(ec, v) );
}
bool on_double( system::error_code& ec, double v )
{
BOOST_JSON_INVOKE_INNER( on_double(ec, v) );
}
bool on_bool( system::error_code& ec, bool v )
{
BOOST_JSON_INVOKE_INNER( on_bool(ec, v) );
}
bool on_null( system::error_code& ec )
{
if( !inner_active_ )
{
*value_ = {};
this->parent_->signal_value();
return true;
}
else
{
return inner_.on_null(ec);
}
}
#undef BOOST_JSON_INVOKE_INNER
};
// path handler
template< class V, class P >
class converting_handler<path_conversion_tag, V, P>
: public scalar_handler<P, error::not_string>
{
private:
V* value_;
bool cleared_ = false;
public:
converting_handler( V* v, P* p )
: converting_handler::scalar_handler(p)
, value_(v)
{}
bool on_string_part( system::error_code&, string_view sv )
{
if( !cleared_ )
{
cleared_ = true;
value_->clear();
}
value_->concat( sv.begin(), sv.end() );
return true;
}
bool on_string( system::error_code&, string_view sv )
{
if( !cleared_ )
value_->clear();
else
cleared_ = false;
value_->concat( sv.begin(), sv.end() );
this->parent_->signal_value();
return true;
}
};
// into_handler
template< class V >
class into_handler
{
private:
using inner_handler_type = get_handler<V, into_handler>;
inner_handler_type inner_;
bool inner_active_ = true;
public:
into_handler( into_handler const& ) = delete;
into_handler& operator=( into_handler const& ) = delete;
public:
static constexpr std::size_t max_object_size = object::max_size();
static constexpr std::size_t max_array_size = array::max_size();
static constexpr std::size_t max_key_size = string::max_size();
static constexpr std::size_t max_string_size = string::max_size();
public:
explicit into_handler( V* v ): inner_( v, this )
{
}
void signal_value()
{
}
bool signal_end(system::error_code&)
{
return true;
}
bool on_document_begin( system::error_code& )
{
return true;
}
bool on_document_end( system::error_code& )
{
inner_active_ = false;
return true;
}
#define BOOST_JSON_INVOKE_INNER(f) \
if( !inner_active_ ) \
{ \
BOOST_JSON_FAIL( ec, error::extra_data ); \
return false; \
} \
else \
return inner_.f
bool on_object_begin( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_object_begin(ec) );
}
bool on_object_end( std::size_t, system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_object_end(ec) );
}
bool on_array_begin( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_array_begin(ec) );
}
bool on_array_end( std::size_t, system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_array_end(ec) );
}
bool on_key_part( string_view sv, std::size_t, system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_key_part(ec, sv) );
}
bool on_key( string_view sv, std::size_t, system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_key(ec, sv) );
}
bool on_string_part( string_view sv, std::size_t, system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_string_part(ec, sv) );
}
bool on_string( string_view sv, std::size_t, system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_string(ec, sv) );
}
bool on_number_part( string_view, system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_number_part(ec) );
}
bool on_int64( std::int64_t v, string_view, system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_int64(ec, v) );
}
bool on_uint64( std::uint64_t v, string_view, system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_uint64(ec, v) );
}
bool on_double( double v, string_view, system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_double(ec, v) );
}
bool on_bool( bool v, system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_bool(ec, v) );
}
bool on_null( system::error_code& ec )
{
BOOST_JSON_INVOKE_INNER( on_null(ec) );
}
bool on_comment_part(string_view, system::error_code&)
{
return true;
}
bool on_comment(string_view, system::error_code&)
{
return true;
}
#undef BOOST_JSON_INVOKE_INNER
};
} // namespace detail
} // namespace boost
} // namespace json
#endif