// Copyright (c) 2022 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/json/ #ifndef TAO_JSON_EVENTS_CAPTURE_HPP #define TAO_JSON_EVENTS_CAPTURE_HPP #include #include #include #include #include "produce.hpp" #include "../forward.hpp" namespace tao::json::events { class virtual_base; namespace capture { template< template< typename... > class Traits = traits, typename ConsumerBase = virtual_base > class value; template< template< typename... > class Traits = traits, typename ConsumerBase = virtual_base > using array = std::initializer_list< value< Traits, ConsumerBase > >; template< template< typename... > class Traits, typename ConsumerBase > struct member; template< template< typename... > class Traits = traits, typename ConsumerBase = virtual_base > using object = std::initializer_list< member< Traits, ConsumerBase > >; } // namespace capture template< template< typename... > class Traits, typename Consumer, typename ConsumerBase > void produce( Consumer& c, const capture::value< Traits, ConsumerBase >& v ) { v.produce( c ); } template< template< typename... > class Traits, typename Consumer, typename ConsumerBase > void produce_elements( Consumer& c, const capture::array< Traits, ConsumerBase >& a ) { for( const auto& e : a ) { e.produce( c ); c.element(); } } template< template< typename... > class Traits, typename Consumer, typename ConsumerBase > void produce( Consumer& c, const capture::array< Traits, ConsumerBase >& a ) { c.begin_array( a.size() ); events::produce_elements( c, a ); c.end_array( a.size() ); } template< template< typename... > class Traits, typename Consumer, typename ConsumerBase > void produce_members( Consumer& c, const capture::object< Traits, ConsumerBase >& o ) { for( const auto& m : o ) { c.key( m.key ); m.produce( c ); c.member(); } } template< template< typename... > class Traits, typename Consumer, typename ConsumerBase > void produce( Consumer& c, const capture::object< Traits, ConsumerBase >& o ) { c.begin_object( o.size() ); events::produce_members( c, o ); c.end_object( o.size() ); } namespace capture { union union_t { const void* p; bool b; char c; signed char sc; unsigned char uc; signed short ss; unsigned short us; signed int si; unsigned int ui; signed long sl; unsigned long ul; signed long long sll; unsigned long long ull; float f; double d; // clang-format off explicit union_t( const void* v ) noexcept : p( v ) {} explicit union_t( const bool v ) noexcept : b( v ) {} explicit union_t( const char v ) noexcept : c( v ) {} explicit union_t( const signed char v ) noexcept : sc( v ) {} explicit union_t( const unsigned char v ) noexcept : uc( v ) {} explicit union_t( const signed short v ) noexcept : ss( v ) {} explicit union_t( const unsigned short v ) noexcept : us( v ) {} explicit union_t( const signed int v ) noexcept : si( v ) {} explicit union_t( const unsigned int v ) noexcept : ui( v ) {} explicit union_t( const signed long v ) noexcept : sl( v ) {} explicit union_t( const unsigned long v ) noexcept : ul( v ) {} explicit union_t( const signed long long v ) noexcept : sll( v ) {} explicit union_t( const unsigned long long v ) noexcept : ull( v ) {} explicit union_t( const float v ) noexcept : f( v ) {} explicit union_t( const double v ) noexcept : d( v ) {} explicit operator bool() const noexcept { return b; } explicit operator char() const noexcept { return c; } explicit operator signed char() const noexcept { return sc; } explicit operator unsigned char() const noexcept { return uc; } explicit operator signed short() const noexcept { return ss; } explicit operator unsigned short() const noexcept { return us; } explicit operator signed int() const noexcept { return si; } explicit operator unsigned int() const noexcept { return ui; } explicit operator signed long() const noexcept { return sl; } explicit operator unsigned long() const noexcept { return ul; } explicit operator signed long long() const noexcept { return sll; } explicit operator unsigned long long() const noexcept { return ull; } explicit operator float() const noexcept { return f; } explicit operator double() const noexcept { return d; } // clang-format on }; template< typename, typename = void > struct capture_traits : std::false_type {}; template< typename T > struct capture_traits< T, std::enable_if_t< std::is_pointer_v< std::decay_t< T > > > > : std::true_type { [[nodiscard]] static const void* to_underlying( const T v ) noexcept { return v; } [[nodiscard]] static auto from_underlying( const union_t& v ) noexcept { return std::decay_t< T >( v.p ); } }; template< typename T > struct capture_traits< T, std::enable_if_t< std::is_arithmetic_v< T > > > : std::true_type { [[nodiscard]] static T to_underlying( const T v ) noexcept { return v; } [[nodiscard]] static T from_underlying( const union_t& v ) noexcept { return static_cast< T >( v ); } }; template< typename T > struct capture_traits< T, std::enable_if_t< std::is_enum_v< T > > > : std::true_type { using underlying_t = std::underlying_type_t< T >; [[nodiscard]] static underlying_t to_underlying( const T v ) noexcept { return static_cast< underlying_t >( v ); } [[nodiscard]] static T from_underlying( const union_t& v ) noexcept { return static_cast< T >( static_cast< underlying_t >( v ) ); } }; namespace internal { template< template< typename... > class Traits, typename Consumer, typename T > void produce_from_underlying( Consumer& c, const union_t& u ) { events::produce< Traits >( c, capture_traits< T >::from_underlying( u ) ); } template< template< typename... > class Traits, typename Consumer, typename T > void produce_from_pointer( Consumer& c, const union_t& u ) { events::produce< Traits >( c, *static_cast< const T* >( u.p ) ); } } // namespace internal template< template< typename... > class Traits, typename ConsumerBase > class value { private: const union_t m_value; using producer_t = void( ConsumerBase&, const union_t& ); producer_t* const m_producer; public: template< typename T, typename = std::enable_if_t< capture_traits< T >::value > > value( const T v ) noexcept : m_value( capture_traits< T >::to_underlying( v ) ), m_producer( &internal::produce_from_underlying< Traits, ConsumerBase, T > ) { static_assert( noexcept( capture_traits< T >::to_underlying( v ) ) ); } template< typename T, typename = std::enable_if_t< !capture_traits< T >::value > > value( const T& v ) noexcept : m_value( &v ), m_producer( &internal::produce_from_pointer< Traits, ConsumerBase, T > ) {} value( const object< Traits, ConsumerBase >& il ) noexcept : m_value( &il ), m_producer( &internal::produce_from_pointer< Traits, ConsumerBase, object< Traits, ConsumerBase > > ) {} void produce( ConsumerBase& c ) const { m_producer( c, m_value ); } }; template< template< typename... > class Traits, typename ConsumerBase > struct member : value< Traits, ConsumerBase > { const std::string_view key; template< typename T > member( const std::string_view k, T&& v ) noexcept : value< Traits, ConsumerBase >( std::forward< T >( v ) ), key( k ) {} template< typename T > member( T&& v ) noexcept : member( Traits< std::decay_t< T > >::template default_key< Traits >::as_string_view(), std::forward< T >( v ) ) {} member( const std::string_view k, const object< Traits, ConsumerBase >& il ) noexcept : value< Traits, ConsumerBase >( il ), key( k ) {} member( const member& ) = delete; member( member&& ) = delete; }; template< template< typename... > class Traits, typename Consumer > class assign_t { private: Consumer& m_consumer; public: explicit assign_t( Consumer& consumer ) noexcept : m_consumer( consumer ) {} assign_t& operator=( const value< Traits, Consumer >& v ) { produce< Traits >( m_consumer, v ); return *this; } template< typename ConsumerBase > assign_t& operator=( const value< Traits, ConsumerBase >& v ) { produce< Traits >( m_consumer, v ); return *this; } template< typename ConsumerBase > assign_t& operator=( const array< Traits, ConsumerBase >& v ) { produce< Traits >( m_consumer, v ); return *this; } template< typename ConsumerBase > assign_t& operator=( const object< Traits, ConsumerBase >& v ) { produce< Traits >( m_consumer, v ); return *this; } [[nodiscard]] Consumer& consumer() noexcept { return m_consumer; } [[nodiscard]] const Consumer& consumer() const noexcept { return m_consumer; } }; template< template< typename... > class Traits, typename Consumer > class array_t { private: Consumer& m_consumer; public: explicit array_t( Consumer& consumer ) noexcept( noexcept( m_consumer.begin_array() ) ) : m_consumer( consumer ) { m_consumer.begin_array(); } array_t( const array_t& ) = delete; array_t( array_t&& ) = delete; ~array_t() { m_consumer.end_array(); } array_t& operator=( const array_t& ) = delete; array_t& operator=( array_t&& ) = delete; array_t& operator+=( const array< Traits, Consumer >& v ) { produce_elements< Traits >( m_consumer, v ); return *this; } template< typename ConsumerBase > array_t& operator+=( const array< Traits, ConsumerBase >& v ) { produce_elements< Traits >( m_consumer, v ); return *this; } template< typename Container > void append( const Container& c ) { for( const auto& e : c ) { this->push_back( e ); } } template< typename V > void push_back( V&& v ) { events::produce< Traits >( m_consumer, std::forward< V >( v ) ); m_consumer.element(); } [[nodiscard]] Consumer& consumer() noexcept { return m_consumer; } [[nodiscard]] const Consumer& consumer() const noexcept { return m_consumer; } }; template< template< typename... > class Traits, typename Consumer > class object_t { private: Consumer& m_consumer; public: explicit object_t( Consumer& consumer ) noexcept( noexcept( m_consumer.begin_object() ) ) : m_consumer( consumer ) { m_consumer.begin_object(); } object_t( const object_t& ) = delete; object_t( object_t&& ) = delete; ~object_t() { m_consumer.end_object(); } object_t& operator=( const object_t& ) = delete; object_t& operator=( object_t&& ) = delete; object_t& operator+=( const object< Traits, Consumer >& v ) { produce_members< Traits >( m_consumer, v ); return *this; } template< typename ConsumerBase > object_t& operator+=( const object< Traits, ConsumerBase >& v ) { produce_members< Traits >( m_consumer, v ); return *this; } template< typename Container > void append( const Container& c ) { for( const auto& [ k, v ] : c ) { this->insert( k, v ); } } template< typename K, typename V > void insert( K&& k, V&& v ) { m_consumer.key( std::forward< K >( k ) ); events::produce< Traits >( m_consumer, std::forward< V >( v ) ); m_consumer.member(); } template< typename V > void insert( V&& v ) { this->insert( Traits< std::decay_t< V > >::template default_key< Traits >::as_string_view(), std::forward< V >( v ) ); } [[nodiscard]] Consumer& consumer() noexcept { return m_consumer; } [[nodiscard]] const Consumer& consumer() const noexcept { return m_consumer; } }; } // namespace capture template< template< typename... > class Traits = traits, typename Consumer > [[nodiscard]] capture::assign_t< Traits, Consumer > assign( Consumer& c ) noexcept( noexcept( capture::assign_t< Traits, Consumer >( c ) ) ) { return capture::assign_t< Traits, Consumer >( c ); } template< template< typename... > class Traits = traits, typename Consumer > [[nodiscard]] capture::assign_t< Traits, Consumer > assign( Consumer&& c ) noexcept( noexcept( assign< Traits >( c ) ) ) { return assign< Traits >( c ); } template< template< typename... > class Traits = traits, typename Consumer > [[nodiscard]] capture::array_t< Traits, Consumer > array( Consumer& c ) noexcept( noexcept( capture::array_t< Traits, Consumer >( c ) ) ) { return capture::array_t< Traits, Consumer >( c ); } template< template< typename... > class Traits = traits, typename Consumer > [[nodiscard]] capture::array_t< Traits, Consumer > array( Consumer&& c ) noexcept( noexcept( array< Traits >( c ) ) ) { return array< Traits >( c ); } template< template< typename... > class Traits = traits, typename Consumer > [[nodiscard]] capture::object_t< Traits, Consumer > object( Consumer& c ) noexcept( noexcept( capture::object_t< Traits, Consumer >( c ) ) ) { return capture::object_t< Traits, Consumer >( c ); } template< template< typename... > class Traits = traits, typename Consumer > [[nodiscard]] capture::object_t< Traits, Consumer > object( Consumer&& c ) noexcept( noexcept( object< Traits >( c ) ) ) { return object< Traits >( c ); } } // namespace tao::json::events #endif