#include "jsongen.hpp" #include "query.hpp" #include static auto d_odd = []( path p, const auto & ) { while ( true ) { if ( p.empty() ) return false; if ( p.tail().empty() ) return true; p = p.tail().tail(); } }; std::string format( path p ) { std::string out; while ( !p.empty() ) { out += "/"; if ( p.front_i() >= 0 ) out += std::to_string( p.front_i() ); else out += p.front_s(); p = p.tail(); } if ( out.size() ) out.erase( out.begin() ); return out; } std::string format( std::stack< int > s ) { std::string out; while ( !s.empty() ) { out = std::to_string( s.top() ) + " " + out; s.pop(); } return out; } int len( path p ) { return p.empty() ? 0 : 1 + len( p.tail() ); } int prefix_chk( path a, path b, int l ) { for ( int i = 0; i < l; ++i ) { if ( a.empty() ) return len( b ); if ( b.empty() ) return -len( a ); ASSERT( a.front_i() == b.front_i() && a.front_s() == b.front_s() ); a = a.tail(); b = b.tail(); } return len( b ) - len( a ); } bool is_odd( const path &, int v ) { return v % 2; } bool is_even( const path &, int v ) { return v % 2 == 0; } int length( const path &, const json_value &o ) { return o.length(); } int int_value( const path &, const json_value &o ) { if ( o.type() == json_type::integer ) return o.int_value(); else return 0; } bool is_empty( const path &, const json_value &o ) { return o.length() == 0; } bool is_array( const path &, const json_value &o ) { return o.type() == json_type::array; } bool is_object( const path &, const json_value &o ) { return o.type() == json_type::object; } bool is_true( const path &, bool b ) { return b; } template< typename query_t > void chk_post( const query_t &q ) { DECLARE( std::stack< int > size ); DECLARE( std::stack< int > idx ); DECLARE( path last ); PSEUDO( "iterating with auto [ p, v ] : q ..." ); for ( auto [ p, v ] : q ) { PSEUDO( "new iteration", "p =", format( p ) ); int diff = prefix_chk( last, p, idx.size() - 1 ); for ( int i = 0; i < diff; ++i ) { TRACE( size.push( 0 ) ); TRACE( idx.push( 0 ) ); } if ( diff < 0 ) { ASSERT( diff == -1, "p should be 1 element shorter than last" ); ASSERT( size.top() == v.length(), "size =", format( size ), "v.length =", v.length() ); if ( idx.top() ) ASSERT( size.top() == idx.top() ); TRACE( size.pop() ); TRACE( idx.pop() ); } if ( !p.empty() ) { if ( p.back_i() >= 0 ) { ASSERT( idx.top() == p.back_i(), "idx =", idx.top(), "back_i =", p.back_i() ); TRACE( ++ idx.top() ); } TRACE( ++ size.top() ); PSEUDO( "current size stack", format( size ) ); PSEUDO( "current idx stack", format( idx ) ); } TRACE( last = p ); } PSEUDO( "... loop finished" ); ASSERT( size.empty() ); ASSERT( last.empty() ); CLEAR(); } void mkpath_( path & ) {} template< typename arg_t, typename... args_t > void mkpath_( path &p, arg_t arg, args_t... args ) { p.extend( arg ); mkpath_( p, args... ); } template< typename... args_t > path mkpath( args_t... args ) { path p; mkpath_( p, args... ); return p; }