// // Copyright (c) 2022 Alan de Freitas (alandefreitas@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/url // #ifndef BOOST_URL_DETAIL_IMPL_FORMAT_ARGS_HPP #define BOOST_URL_DETAIL_IMPL_FORMAT_ARGS_HPP namespace boost { namespace urls { namespace detail { template< class A, typename std::enable_if< !std::is_integral< typename std::decay::type>::value, int>::type = 0> std::size_t get_uvalue( A&& ) { return 0; } template< class A, typename std::enable_if< std::is_integral< typename std::decay::type>::value && std::is_signed< typename std::decay::type>::value, int>::type = 0> std::size_t get_uvalue( A&& a ) { if (a > 0) return static_cast(a); return 0; } template< class A, typename std::enable_if< std::is_integral< typename std::decay::type>::value && std::is_unsigned< typename std::decay::type>::value, int>::type = 0> std::size_t get_uvalue( A&& a ) { return static_cast(a); } BOOST_URL_DECL std::size_t get_uvalue( core::string_view a ); BOOST_URL_DECL std::size_t get_uvalue( char a ); template format_arg:: format_arg( A&& a ) : arg_( &a ) , measure_( &measure_impl ) , fmt_( &format_impl ) , value_( get_uvalue(std::forward(a) )) , ignore_( std::is_same::value ) {} template format_arg:: format_arg( named_arg&& a ) : arg_( &a.value ) , measure_( &measure_impl ) , fmt_( &format_impl ) , name_( a.name ) , value_( get_uvalue(a.value)) {} template format_arg:: format_arg( core::string_view name, A&& a ) : arg_( &a ) , measure_( &measure_impl ) , fmt_( &format_impl ) , name_( name ) , value_( get_uvalue(a) ) {} // define the type-erased implementations that // depends on everything: the context types, // formatters, and type erased args template void format_arg:: measure_impl( format_parse_context& pctx, measure_context& mctx, grammar::lut_chars const& cs, void const* a ) { using ref_t = typename std::remove_cv< typename std::remove_reference::type>::type; A const& ref = *static_cast( const_cast( a ) ); formatter f; pctx.advance_to( f.parse(pctx) ); mctx.advance_to( f.measure( ref, mctx, cs ) ); } template void format_arg:: format_impl( format_parse_context& pctx, format_context& fctx, grammar::lut_chars const& cs, void const* a ) { using ref_t = typename std::remove_cv< typename std::remove_reference::type>::type; A const& ref = *static_cast( const_cast( a ) ); formatter f; pctx.advance_to( f.parse(pctx) ); fctx.advance_to( f.format( ref, fctx, cs ) ); } // We point to formatter where // the format_arg variant would store monostate template <> struct formatter { public: char const* parse(format_parse_context& ctx) const { return parse_empty_spec( ctx.begin(), ctx.end()); } std::size_t measure( ignore_format, measure_context& ctx, grammar::lut_chars const&) const { return ctx.out(); } char* format( ignore_format, format_context& ctx, grammar::lut_chars const&) const { return ctx.out(); } // We ignore the modifiers in all replacements // for now static char const* parse_empty_spec( char const* it, char const* end) { // [it, end] -> "} suffix" BOOST_ASSERT(it != end); ignore_unused(end); // Should be always empty/valid as an // implementation detail BOOST_ASSERT(*it == '}'); /* if (*it != '}') urls::detail::throw_invalid_argument(); */ return it; } }; inline std::size_t measure_one( char c, grammar::lut_chars const& unreserved) { // '%' must be reserved BOOST_ASSERT(! unreserved('%')); return 1 + !unreserved(c) * 2; } inline void encode_one( char*& out, char c, grammar::lut_chars const& unreserved) { // '%' must be reserved BOOST_ASSERT(! unreserved('%')); if(unreserved(c)) { *out++ = c; return; } *out++ = '%'; *out++ = urls::detail::hexdigs[0][c>>4]; *out++ = urls::detail::hexdigs[0][c&0xf]; } // get an unsigned value from format_args BOOST_URL_DECL void get_width_from_args( std::size_t arg_idx, core::string_view arg_name, format_args args, std::size_t& w); // formatter for string view template <> struct formatter { private: char fill = ' '; char align = '\0'; std::size_t width = 0; std::size_t width_idx = std::size_t(-1); core::string_view width_name; public: BOOST_URL_DECL char const* parse(format_parse_context& ctx); BOOST_URL_DECL std::size_t measure( core::string_view str, measure_context& ctx, grammar::lut_chars const& cs) const; BOOST_URL_DECL char* format( core::string_view str, format_context& ctx, grammar::lut_chars const& cs) const; }; // formatter for anything convertible to a // string view template struct formatter< T, typename std::enable_if< std::is_convertible< T, core::string_view>::value>::type> { formatter impl_; public: char const* parse(format_parse_context& ctx) { return impl_.parse(ctx); } std::size_t measure( core::string_view str, measure_context& ctx, grammar::lut_chars const& cs) const { return impl_.measure(str, ctx, cs); } char* format(core::string_view str, format_context& ctx, grammar::lut_chars const& cs) const { return impl_.format(str, ctx, cs); } }; template <> struct formatter { formatter impl_; public: char const* parse(format_parse_context& ctx) { return impl_.parse(ctx); } std::size_t measure( char c, measure_context& ctx, grammar::lut_chars const& cs) const { return impl_.measure({&c, 1}, ctx, cs); } char* format( char c, format_context& ctx, grammar::lut_chars const& cs) const { return impl_.format({&c, 1}, ctx, cs); } }; // formatters for a single integer class integer_formatter_impl { char fill = ' '; char align = '\0'; char sign = '-'; bool zeros = false; std::size_t width = 0; std::size_t width_idx = std::size_t(-1); core::string_view width_name; public: BOOST_URL_DECL char const* parse(format_parse_context& ctx); BOOST_URL_DECL std::size_t measure( unsigned long long int v, measure_context& ctx, grammar::lut_chars const& cs) const; BOOST_URL_DECL std::size_t measure( long long int v, measure_context& ctx, grammar::lut_chars const& cs) const; BOOST_URL_DECL char* format( unsigned long long int v, format_context& ctx, grammar::lut_chars const& cs) const; BOOST_URL_DECL char* format( long long int v, format_context& ctx, grammar::lut_chars const& cs) const; }; template struct formatter< T, typename std::enable_if< mp11::mp_contains, T>::value>::type> { private: integer_formatter_impl impl_; using base_value_type = typename std::conditional< std::is_unsigned::value, unsigned long long int, long long int >::type; public: char const* parse(format_parse_context& ctx) { return impl_.parse(ctx); } std::size_t measure( T v, measure_context& ctx, grammar::lut_chars const& cs) const { return impl_.measure( static_cast(v), ctx, cs); } char* format(T v, format_context& ctx, grammar::lut_chars const& cs) const { return impl_.format( static_cast(v), ctx, cs); } }; } // detail } // url } // boost #endif