123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- //
- // Copyright (c) 2022 Alan de Freitas ([email protected])
- //
- // 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<A>::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<A>::type>::value &&
- std::is_signed<
- typename std::decay<A>::type>::value,
- int>::type = 0>
- std::size_t
- get_uvalue( A&& a )
- {
- if (a > 0)
- return static_cast<std::size_t>(a);
- return 0;
- }
- template<
- class A,
- typename std::enable_if<
- std::is_integral<
- typename std::decay<A>::type>::value &&
- std::is_unsigned<
- typename std::decay<A>::type>::value,
- int>::type = 0>
- std::size_t
- get_uvalue( A&& a )
- {
- return static_cast<std::size_t>(a);
- }
- BOOST_URL_DECL
- std::size_t
- get_uvalue( core::string_view a );
- BOOST_URL_DECL
- std::size_t
- get_uvalue( char a );
- template<class A>
- format_arg::
- format_arg( A&& a )
- : arg_( &a )
- , measure_( &measure_impl<A> )
- , fmt_( &format_impl<A> )
- , value_( get_uvalue(std::forward<A>(a) ))
- , ignore_( std::is_same<A, ignore_format>::value )
- {}
- template<class A>
- format_arg::
- format_arg( named_arg<A>&& a )
- : arg_( &a.value )
- , measure_( &measure_impl<A> )
- , fmt_( &format_impl<A> )
- , name_( a.name )
- , value_( get_uvalue(a.value))
- {}
- template<class A>
- format_arg::
- format_arg( core::string_view name, A&& a )
- : arg_( &a )
- , measure_( &measure_impl<A> )
- , fmt_( &format_impl<A> )
- , name_( name )
- , value_( get_uvalue(a) )
- {}
- // define the type-erased implementations that
- // depends on everything: the context types,
- // formatters, and type erased args
- template <class A>
- 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<A>::type>::type;
- A const& ref = *static_cast<ref_t*>(
- const_cast<void*>( a ) );
- formatter<ref_t> f;
- pctx.advance_to( f.parse(pctx) );
- mctx.advance_to( f.measure( ref, mctx, cs ) );
- }
- template <class A>
- 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<A>::type>::type;
- A const& ref = *static_cast<ref_t*>(
- const_cast<void*>( a ) );
- formatter<ref_t> f;
- pctx.advance_to( f.parse(pctx) );
- fctx.advance_to( f.format( ref, fctx, cs ) );
- }
- // We point to formatter<ignore_format> where
- // the format_arg variant would store monostate
- template <>
- struct formatter<ignore_format>
- {
- 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<core::string_view>
- {
- 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 <class T>
- struct formatter<
- T, typename std::enable_if<
- std::is_convertible<
- T, core::string_view>::value>::type>
- {
- formatter<core::string_view> 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<char>
- {
- formatter<core::string_view> 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 <class T>
- struct formatter<
- T, typename std::enable_if<
- mp11::mp_contains<mp11::mp_list<
- short int,
- int,
- long int,
- long long int,
- unsigned short int,
- unsigned int,
- unsigned long int,
- unsigned long long int>, T>::value>::type>
- {
- private:
- integer_formatter_impl impl_;
- using base_value_type = typename std::conditional<
- std::is_unsigned<T>::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<base_value_type>(v), ctx, cs);
- }
- char*
- format(T v, format_context& ctx, grammar::lut_chars const& cs) const
- {
- return impl_.format(
- static_cast<base_value_type>(v), ctx, cs);
- }
- };
- } // detail
- } // url
- } // boost
- #endif
|