// // 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_FORMAT_ARGS_HPP #define BOOST_URL_DETAIL_FORMAT_ARGS_HPP #include #include #include #include // This file implements functions and classes to // type-erase format arguments. namespace boost { namespace urls { namespace detail { // state of the format string. It basically keeps // track of where we are in the format string. class format_parse_context { char const* begin_; char const* end_; std::size_t arg_id_ = 0; public: constexpr format_parse_context( char const* first, char const* last, std::size_t arg_id = 0) : begin_( first ) , end_( last ) , arg_id_( arg_id ) {} constexpr format_parse_context( core::string_view fmt, std::size_t arg_id = 0) : format_parse_context( fmt.data(), fmt.data() + fmt.size(), arg_id ) {} constexpr char const* begin() const noexcept { return begin_; } constexpr char const* end() const noexcept { return end_; } BOOST_CXX14_CONSTEXPR void advance_to( char const* it ) { begin_ = it; } std::size_t next_arg_id() { return arg_id_++; } }; // State of the destination string class format_context; class measure_context; struct ignore_format {}; template struct named_arg { core::string_view name; T const& value; named_arg(core::string_view n, T const& v) : name(n) , value(v) {} }; // A type erased format argument class format_arg { void const* arg_; void (*measure_)( format_parse_context&, measure_context&, grammar::lut_chars const&, void const* ); void (*fmt_)( format_parse_context&, format_context&, grammar::lut_chars const&, void const* ); core::string_view name_; std::size_t value_ = 0; bool ignore_ = false; template static void measure_impl( format_parse_context& pctx, measure_context& mctx, grammar::lut_chars const& cs, void const* a ); template static void format_impl( format_parse_context& pctx, format_context& fctx, grammar::lut_chars const& cs, void const* a ); public: template format_arg( A&& a ); template format_arg( named_arg&& a ); template format_arg( core::string_view name, A&& a ); format_arg() : format_arg(ignore_format{}) {} explicit operator bool() const noexcept { return !ignore_; } void measure( format_parse_context& pctx, measure_context& mctx, grammar::lut_chars const& cs) { measure_( pctx, mctx, cs, arg_ ); } void format( format_parse_context& pctx, format_context& fctx, grammar::lut_chars const& cs ) { fmt_( pctx, fctx, cs, arg_ ); } core::string_view name() const { return name_; } std::size_t value() const { return value_; } }; // create temp stack storage for type erased args template< class... Args > std::array make_format_args( Args&&... args ) { return {{ std::forward(args)... }}; } // reference to an array of format_args class format_args { format_arg const* p_{nullptr}; std::size_t n_{0}; public: format_args( detail::format_arg const* first, detail::format_arg const* last ) noexcept : p_(first) , n_(static_cast(last - first)) {} template < std::size_t N > format_args( std::array const& store ) noexcept : p_(store.data()) , n_(store.size()) {} format_arg get( std::size_t i ) const noexcept { if (i < n_) return p_[i]; return {}; } format_arg get( core::string_view name ) const noexcept { for (std::size_t i = 0; i < n_; ++i) { if (p_[i].name() == name) return p_[i]; } return {}; } }; // define the format_context after format_args class format_context { format_args args_; char* out_; public: format_context( char* out, format_args args ) : args_( args ) , out_( out ) {} format_args args() const noexcept { return args_; } format_arg arg( std::size_t id ) const noexcept { return args_.get( id ); } format_arg arg( core::string_view name ) const noexcept { return args_.get( name ); } char* out() { return out_; } void advance_to( char* it ) { out_ = it; } }; // define the measure_context after format_args class measure_context { format_args args_; std::size_t out_; public: measure_context( format_args args ) : measure_context(0, args) {} measure_context( std::size_t out, format_args args ) : args_( args ) , out_( out ) {} format_args args() const noexcept { return args_; } format_arg arg( std::size_t id ) const noexcept { return args_.get( id ); } format_arg arg( core::string_view name ) const noexcept { return args_.get( name ); } std::size_t out() { return out_; } void advance_to( std::size_t n ) { out_ = n; } }; // fwd declare the formatter template struct formatter; } // detail } // url } // boost #include #endif