//
// 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