1  
//
1  
//
2  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
2  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/boostorg/url
7  
// Official repository: https://github.com/boostorg/url
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_URL_DETAIL_IMPL_FORMAT_ARGS_HPP
10  
#ifndef BOOST_URL_DETAIL_IMPL_FORMAT_ARGS_HPP
11  
#define BOOST_URL_DETAIL_IMPL_FORMAT_ARGS_HPP
11  
#define BOOST_URL_DETAIL_IMPL_FORMAT_ARGS_HPP
12  

12  

13  
namespace boost {
13  
namespace boost {
14  
namespace urls {
14  
namespace urls {
15  
namespace detail {
15  
namespace detail {
16  

16  

17  
template<
17  
template<
18  
    class A,
18  
    class A,
19  
    typename std::enable_if<
19  
    typename std::enable_if<
20  
        !std::is_integral<
20  
        !std::is_integral<
21  
            typename std::decay<A>::type>::value,
21  
            typename std::decay<A>::type>::value,
22  
                int>::type = 0>
22  
                int>::type = 0>
23  
std::size_t
23  
std::size_t
24  
get_uvalue( A&& )
24  
get_uvalue( A&& )
25  
{
25  
{
26  
    return 0;
26  
    return 0;
27  
}
27  
}
28  

28  

29  
template<
29  
template<
30  
    class A,
30  
    class A,
31  
    typename std::enable_if<
31  
    typename std::enable_if<
32  
        std::is_integral<
32  
        std::is_integral<
33  
            typename std::decay<A>::type>::value &&
33  
            typename std::decay<A>::type>::value &&
34  
        std::is_signed<
34  
        std::is_signed<
35  
            typename std::decay<A>::type>::value,
35  
            typename std::decay<A>::type>::value,
36  
        int>::type = 0>
36  
        int>::type = 0>
37  
std::size_t
37  
std::size_t
38  
get_uvalue( A&& a )
38  
get_uvalue( A&& a )
39  
{
39  
{
40  
    if (a > 0)
40  
    if (a > 0)
41  
        return static_cast<std::size_t>(a);
41  
        return static_cast<std::size_t>(a);
42  
    return 0;
42  
    return 0;
43  
}
43  
}
44  

44  

45  
template<
45  
template<
46  
    class A,
46  
    class A,
47  
    typename std::enable_if<
47  
    typename std::enable_if<
48  
        std::is_integral<
48  
        std::is_integral<
49  
            typename std::decay<A>::type>::value &&
49  
            typename std::decay<A>::type>::value &&
50  
            std::is_unsigned<
50  
            std::is_unsigned<
51  
                typename std::decay<A>::type>::value,
51  
                typename std::decay<A>::type>::value,
52  
        int>::type = 0>
52  
        int>::type = 0>
53  
std::size_t
53  
std::size_t
54  
get_uvalue( A&& a )
54  
get_uvalue( A&& a )
55  
{
55  
{
56  
    return static_cast<std::size_t>(a);
56  
    return static_cast<std::size_t>(a);
57  
}
57  
}
58  

58  

59  
BOOST_URL_DECL
59  
BOOST_URL_DECL
60  
std::size_t
60  
std::size_t
61  
get_uvalue( core::string_view a );
61  
get_uvalue( core::string_view a );
62  

62  

63  
BOOST_URL_DECL
63  
BOOST_URL_DECL
64  
std::size_t
64  
std::size_t
65  
get_uvalue( char a );
65  
get_uvalue( char a );
66  

66  

67  
template<class A>
67  
template<class A>
68  
format_arg::
68  
format_arg::
69  
format_arg( A&& a )
69  
format_arg( A&& a )
70  
    : arg_( &a )
70  
    : arg_( &a )
71  
    , measure_( &measure_impl<A> )
71  
    , measure_( &measure_impl<A> )
72  
    , fmt_( &format_impl<A> )
72  
    , fmt_( &format_impl<A> )
73  
    , value_( get_uvalue(std::forward<A>(a) ))
73  
    , value_( get_uvalue(std::forward<A>(a) ))
74  
    , ignore_( std::is_same<A, ignore_format>::value )
74  
    , ignore_( std::is_same<A, ignore_format>::value )
75  
{}
75  
{}
76  

76  

77  
template<class A>
77  
template<class A>
78  
format_arg::
78  
format_arg::
79  
format_arg( named_arg<A>&& a )
79  
format_arg( named_arg<A>&& a )
80  
    : arg_( &a.value )
80  
    : arg_( &a.value )
81  
    , measure_( &measure_impl<A> )
81  
    , measure_( &measure_impl<A> )
82  
    , fmt_( &format_impl<A> )
82  
    , fmt_( &format_impl<A> )
83  
    , name_( a.name )
83  
    , name_( a.name )
84  
    , value_( get_uvalue(a.value))
84  
    , value_( get_uvalue(a.value))
85  
{}
85  
{}
86  

86  

87  
template<class A>
87  
template<class A>
88  
format_arg::
88  
format_arg::
89  
format_arg( core::string_view name, A&& a )
89  
format_arg( core::string_view name, A&& a )
90  
    : arg_( &a )
90  
    : arg_( &a )
91  
    , measure_( &measure_impl<A> )
91  
    , measure_( &measure_impl<A> )
92  
    , fmt_( &format_impl<A> )
92  
    , fmt_( &format_impl<A> )
93  
    , name_( name )
93  
    , name_( name )
94  
    , value_( get_uvalue(a) )
94  
    , value_( get_uvalue(a) )
95  
{}
95  
{}
96  

96  

97  
// define the type-erased implementations that
97  
// define the type-erased implementations that
98  
// depends on everything: the context types,
98  
// depends on everything: the context types,
99  
// formatters, and type erased args
99  
// formatters, and type erased args
100  
template <class A>
100  
template <class A>
101  
void
101  
void
102  
format_arg::
102  
format_arg::
103  
measure_impl(
103  
measure_impl(
104  
    format_parse_context& pctx,
104  
    format_parse_context& pctx,
105  
    measure_context& mctx,
105  
    measure_context& mctx,
106  
    grammar::lut_chars const& cs,
106  
    grammar::lut_chars const& cs,
107  
    void const* a )
107  
    void const* a )
108  
{
108  
{
109  
    using ref_t = typename std::remove_cv<
109  
    using ref_t = typename std::remove_cv<
110  
        typename std::remove_reference<A>::type>::type;
110  
        typename std::remove_reference<A>::type>::type;
111  
    A const& ref = *static_cast<ref_t*>(
111  
    A const& ref = *static_cast<ref_t*>(
112  
        const_cast<void*>( a ) );
112  
        const_cast<void*>( a ) );
113  
    formatter<ref_t> f;
113  
    formatter<ref_t> f;
114  
    pctx.advance_to( f.parse(pctx) );
114  
    pctx.advance_to( f.parse(pctx) );
115  
    mctx.advance_to( f.measure( ref, mctx, cs ) );
115  
    mctx.advance_to( f.measure( ref, mctx, cs ) );
116  
}
116  
}
117  

117  

118  
template <class A>
118  
template <class A>
119  
void
119  
void
120  
format_arg::
120  
format_arg::
121  
format_impl(
121  
format_impl(
122  
    format_parse_context& pctx,
122  
    format_parse_context& pctx,
123  
    format_context& fctx,
123  
    format_context& fctx,
124  
    grammar::lut_chars const& cs,
124  
    grammar::lut_chars const& cs,
125  
    void const* a )
125  
    void const* a )
126  
{
126  
{
127  
    using ref_t = typename std::remove_cv<
127  
    using ref_t = typename std::remove_cv<
128  
        typename std::remove_reference<A>::type>::type;
128  
        typename std::remove_reference<A>::type>::type;
129  
    A const& ref = *static_cast<ref_t*>(
129  
    A const& ref = *static_cast<ref_t*>(
130  
            const_cast<void*>( a ) );
130  
            const_cast<void*>( a ) );
131  
    formatter<ref_t> f;
131  
    formatter<ref_t> f;
132  
    pctx.advance_to( f.parse(pctx) );
132  
    pctx.advance_to( f.parse(pctx) );
133  
    fctx.advance_to( f.format( ref, fctx, cs ) );
133  
    fctx.advance_to( f.format( ref, fctx, cs ) );
134  
}
134  
}
135  

135  

136  
// We point to formatter<ignore_format> where
136  
// We point to formatter<ignore_format> where
137  
// the format_arg variant would store monostate
137  
// the format_arg variant would store monostate
138  
template <>
138  
template <>
139  
struct formatter<ignore_format>
139  
struct formatter<ignore_format>
140  
{
140  
{
141  
public:
141  
public:
142  
    char const*
142  
    char const*
143  
    parse(format_parse_context& ctx) const
143  
    parse(format_parse_context& ctx) const
144  
    {
144  
    {
145  
        return parse_empty_spec(
145  
        return parse_empty_spec(
146  
            ctx.begin(), ctx.end());
146  
            ctx.begin(), ctx.end());
147  
    }
147  
    }
148  

148  

149  
    std::size_t
149  
    std::size_t
150  
    measure(
150  
    measure(
151  
        ignore_format,
151  
        ignore_format,
152  
        measure_context& ctx,
152  
        measure_context& ctx,
153  
        grammar::lut_chars const&) const
153  
        grammar::lut_chars const&) const
154  
    {
154  
    {
155  
        return ctx.out();
155  
        return ctx.out();
156  
    }
156  
    }
157  

157  

158  
    char*
158  
    char*
159  
    format(
159  
    format(
160  
        ignore_format,
160  
        ignore_format,
161  
        format_context& ctx,
161  
        format_context& ctx,
162  
        grammar::lut_chars const&) const
162  
        grammar::lut_chars const&) const
163  
    {
163  
    {
164  
        return ctx.out();
164  
        return ctx.out();
165  
    }
165  
    }
166  

166  

167  
    // We ignore the modifiers in all replacements
167  
    // We ignore the modifiers in all replacements
168  
    // for now
168  
    // for now
169  
    static
169  
    static
170  
    char const*
170  
    char const*
171  
    parse_empty_spec(
171  
    parse_empty_spec(
172  
        char const* it,
172  
        char const* it,
173  
        char const* end)
173  
        char const* end)
174  
    {
174  
    {
175  
        // [it, end] -> "} suffix"
175  
        // [it, end] -> "} suffix"
176  
        BOOST_ASSERT(it != end);
176  
        BOOST_ASSERT(it != end);
177  
        ignore_unused(end);
177  
        ignore_unused(end);
178  
        // Should be always empty/valid as an
178  
        // Should be always empty/valid as an
179  
        // implementation detail
179  
        // implementation detail
180  
        BOOST_ASSERT(*it == '}');
180  
        BOOST_ASSERT(*it == '}');
181  
        /*
181  
        /*
182  
        if (*it != '}')
182  
        if (*it != '}')
183  
            urls::detail::throw_invalid_argument();
183  
            urls::detail::throw_invalid_argument();
184  
        */
184  
        */
185  
        return it;
185  
        return it;
186  
    }
186  
    }
187  
};
187  
};
188  

188  

189  
inline
189  
inline
190  
std::size_t
190  
std::size_t
191  
measure_one(
191  
measure_one(
192  
    char c,
192  
    char c,
193  
    grammar::lut_chars const& unreserved)
193  
    grammar::lut_chars const& unreserved)
194  
{
194  
{
195  
    // '%' must be reserved
195  
    // '%' must be reserved
196  
    BOOST_ASSERT(! unreserved('%'));
196  
    BOOST_ASSERT(! unreserved('%'));
197  
    return 1 + !unreserved(c) * 2;
197  
    return 1 + !unreserved(c) * 2;
198  
}
198  
}
199  

199  

200  
inline
200  
inline
201  
void
201  
void
202  
encode_one(
202  
encode_one(
203  
    char*& out,
203  
    char*& out,
204  
    char c,
204  
    char c,
205  
    grammar::lut_chars const& unreserved)
205  
    grammar::lut_chars const& unreserved)
206  
{
206  
{
207  
    // '%' must be reserved
207  
    // '%' must be reserved
208  
    BOOST_ASSERT(! unreserved('%'));
208  
    BOOST_ASSERT(! unreserved('%'));
209  
    if(unreserved(c))
209  
    if(unreserved(c))
210  
    {
210  
    {
211  
        *out++ = c;
211  
        *out++ = c;
212  
        return;
212  
        return;
213  
    }
213  
    }
214  
    *out++ = '%';
214  
    *out++ = '%';
215 -
    *out++ = urls::detail::hexdigs[0][c>>4];
215 +
    auto uc = static_cast<unsigned char>(c);
216 -
    *out++ = urls::detail::hexdigs[0][c&0xf];
216 +
    *out++ = urls::detail::hexdigs[0][uc>>4];
 
217 +
    *out++ = urls::detail::hexdigs[0][uc&0xf];
217  
}
218  
}
218  

219  

219  
// get an unsigned value from format_args
220  
// get an unsigned value from format_args
220  
BOOST_URL_DECL
221  
BOOST_URL_DECL
221  
void
222  
void
222  
get_width_from_args(
223  
get_width_from_args(
223  
    std::size_t arg_idx,
224  
    std::size_t arg_idx,
224  
    core::string_view arg_name,
225  
    core::string_view arg_name,
225  
    format_args args,
226  
    format_args args,
226  
    std::size_t& w);
227  
    std::size_t& w);
227  

228  

228  
// formatter for string view
229  
// formatter for string view
229  
template <>
230  
template <>
230  
struct formatter<core::string_view>
231  
struct formatter<core::string_view>
231  
{
232  
{
232  
private:
233  
private:
233  
    char fill = ' ';
234  
    char fill = ' ';
234  
    char align = '\0';
235  
    char align = '\0';
235  
    std::size_t width = 0;
236  
    std::size_t width = 0;
236  
    std::size_t width_idx = std::size_t(-1);
237  
    std::size_t width_idx = std::size_t(-1);
237  
    core::string_view width_name;
238  
    core::string_view width_name;
238  

239  

239  
public:
240  
public:
240  
    BOOST_URL_DECL
241  
    BOOST_URL_DECL
241  
    char const*
242  
    char const*
242  
    parse(format_parse_context& ctx);
243  
    parse(format_parse_context& ctx);
243  

244  

244  
    BOOST_URL_DECL
245  
    BOOST_URL_DECL
245  
    std::size_t
246  
    std::size_t
246  
    measure(
247  
    measure(
247  
        core::string_view str,
248  
        core::string_view str,
248  
        measure_context& ctx,
249  
        measure_context& ctx,
249  
        grammar::lut_chars const& cs) const;
250  
        grammar::lut_chars const& cs) const;
250  

251  

251  
    BOOST_URL_DECL
252  
    BOOST_URL_DECL
252  
    char*
253  
    char*
253  
    format(
254  
    format(
254  
        core::string_view str,
255  
        core::string_view str,
255  
        format_context& ctx,
256  
        format_context& ctx,
256  
        grammar::lut_chars const& cs) const;
257  
        grammar::lut_chars const& cs) const;
257  
};
258  
};
258  

259  

259  
// formatter for anything convertible to a
260  
// formatter for anything convertible to a
260  
// string view
261  
// string view
261  
template <class T>
262  
template <class T>
262  
struct formatter<
263  
struct formatter<
263  
    T, typename std::enable_if<
264  
    T, typename std::enable_if<
264  
        std::is_convertible<
265  
        std::is_convertible<
265  
            T, core::string_view>::value>::type>
266  
            T, core::string_view>::value>::type>
266  
{
267  
{
267  
    formatter<core::string_view> impl_;
268  
    formatter<core::string_view> impl_;
268  

269  

269  
public:
270  
public:
270  
    char const*
271  
    char const*
271  
    parse(format_parse_context& ctx)
272  
    parse(format_parse_context& ctx)
272  
    {
273  
    {
273  
        return impl_.parse(ctx);
274  
        return impl_.parse(ctx);
274  
    }
275  
    }
275  

276  

276  
    std::size_t
277  
    std::size_t
277  
    measure(
278  
    measure(
278  
        core::string_view str,
279  
        core::string_view str,
279  
        measure_context& ctx,
280  
        measure_context& ctx,
280  
        grammar::lut_chars const& cs) const
281  
        grammar::lut_chars const& cs) const
281  
    {
282  
    {
282  
        return impl_.measure(str, ctx, cs);
283  
        return impl_.measure(str, ctx, cs);
283  
    }
284  
    }
284  

285  

285  
    char*
286  
    char*
286  
    format(core::string_view str, format_context& ctx, grammar::lut_chars const& cs) const
287  
    format(core::string_view str, format_context& ctx, grammar::lut_chars const& cs) const
287  
    {
288  
    {
288  
        return impl_.format(str, ctx, cs);
289  
        return impl_.format(str, ctx, cs);
289  
    }
290  
    }
290  
};
291  
};
291  

292  

292  
template <>
293  
template <>
293  
struct formatter<char>
294  
struct formatter<char>
294  
{
295  
{
295  
    formatter<core::string_view> impl_;
296  
    formatter<core::string_view> impl_;
296  

297  

297  
public:
298  
public:
298  
    char const*
299  
    char const*
299  
    parse(format_parse_context& ctx)
300  
    parse(format_parse_context& ctx)
300  
    {
301  
    {
301  
        return impl_.parse(ctx);
302  
        return impl_.parse(ctx);
302  
    }
303  
    }
303  

304  

304  
    std::size_t
305  
    std::size_t
305  
    measure(
306  
    measure(
306  
        char c,
307  
        char c,
307  
        measure_context& ctx,
308  
        measure_context& ctx,
308  
        grammar::lut_chars const& cs) const
309  
        grammar::lut_chars const& cs) const
309  
    {
310  
    {
310  
        return impl_.measure({&c, 1}, ctx, cs);
311  
        return impl_.measure({&c, 1}, ctx, cs);
311  
    }
312  
    }
312  

313  

313  
    char*
314  
    char*
314  
    format(
315  
    format(
315  
        char c,
316  
        char c,
316  
        format_context& ctx,
317  
        format_context& ctx,
317  
        grammar::lut_chars const& cs) const
318  
        grammar::lut_chars const& cs) const
318  
    {
319  
    {
319  
        return impl_.format({&c, 1}, ctx, cs);
320  
        return impl_.format({&c, 1}, ctx, cs);
320  
    }
321  
    }
321  
};
322  
};
322  

323  

323  
// formatters for a single integer
324  
// formatters for a single integer
324  
class integer_formatter_impl
325  
class integer_formatter_impl
325  
{
326  
{
326  
    char fill = ' ';
327  
    char fill = ' ';
327  
    char align = '\0';
328  
    char align = '\0';
328  
    char sign = '-';
329  
    char sign = '-';
329  
    bool zeros = false;
330  
    bool zeros = false;
330  
    std::size_t width = 0;
331  
    std::size_t width = 0;
331  
    std::size_t width_idx = std::size_t(-1);
332  
    std::size_t width_idx = std::size_t(-1);
332  
    core::string_view width_name;
333  
    core::string_view width_name;
333  

334  

334  
public:
335  
public:
335  
    BOOST_URL_DECL
336  
    BOOST_URL_DECL
336  
    char const*
337  
    char const*
337  
    parse(format_parse_context& ctx);
338  
    parse(format_parse_context& ctx);
338  

339  

339  
    BOOST_URL_DECL
340  
    BOOST_URL_DECL
340  
    std::size_t
341  
    std::size_t
341  
    measure(
342  
    measure(
342  
        unsigned long long int v,
343  
        unsigned long long int v,
343  
        measure_context& ctx,
344  
        measure_context& ctx,
344  
        grammar::lut_chars const& cs) const;
345  
        grammar::lut_chars const& cs) const;
345  

346  

346  
    BOOST_URL_DECL
347  
    BOOST_URL_DECL
347  
    std::size_t
348  
    std::size_t
348  
    measure(
349  
    measure(
349  
        long long int v,
350  
        long long int v,
350  
        measure_context& ctx,
351  
        measure_context& ctx,
351  
        grammar::lut_chars const& cs) const;
352  
        grammar::lut_chars const& cs) const;
352  

353  

353  
    BOOST_URL_DECL
354  
    BOOST_URL_DECL
354  
    char*
355  
    char*
355  
    format(
356  
    format(
356  
        unsigned long long int v,
357  
        unsigned long long int v,
357  
        format_context& ctx,
358  
        format_context& ctx,
358  
        grammar::lut_chars const& cs) const;
359  
        grammar::lut_chars const& cs) const;
359  

360  

360  
    BOOST_URL_DECL
361  
    BOOST_URL_DECL
361  
    char*
362  
    char*
362  
    format(
363  
    format(
363  
        long long int v,
364  
        long long int v,
364  
        format_context& ctx,
365  
        format_context& ctx,
365  
        grammar::lut_chars const& cs) const;
366  
        grammar::lut_chars const& cs) const;
366  
};
367  
};
367  

368  

368  
template <class T>
369  
template <class T>
369  
struct formatter<
370  
struct formatter<
370  
    T, typename std::enable_if<
371  
    T, typename std::enable_if<
371  
        mp11::mp_contains<mp11::mp_list<
372  
        mp11::mp_contains<mp11::mp_list<
372  
            short int,
373  
            short int,
373  
            int,
374  
            int,
374  
            long int,
375  
            long int,
375  
            long long int,
376  
            long long int,
376  
            unsigned short int,
377  
            unsigned short int,
377  
            unsigned int,
378  
            unsigned int,
378  
            unsigned long int,
379  
            unsigned long int,
379  
            unsigned long long int>, T>::value>::type>
380  
            unsigned long long int>, T>::value>::type>
380  
{
381  
{
381  
private:
382  
private:
382  
    integer_formatter_impl impl_;
383  
    integer_formatter_impl impl_;
383  
    using base_value_type = typename std::conditional<
384  
    using base_value_type = typename std::conditional<
384  
        std::is_unsigned<T>::value,
385  
        std::is_unsigned<T>::value,
385  
        unsigned long long int,
386  
        unsigned long long int,
386  
        long long int
387  
        long long int
387  
        >::type;
388  
        >::type;
388  

389  

389  
public:
390  
public:
390  
    char const*
391  
    char const*
391  
    parse(format_parse_context& ctx)
392  
    parse(format_parse_context& ctx)
392  
    {
393  
    {
393  
        return impl_.parse(ctx);
394  
        return impl_.parse(ctx);
394  
    }
395  
    }
395  

396  

396  
    std::size_t
397  
    std::size_t
397  
    measure(
398  
    measure(
398  
        T v,
399  
        T v,
399  
        measure_context& ctx,
400  
        measure_context& ctx,
400  
        grammar::lut_chars const& cs) const
401  
        grammar::lut_chars const& cs) const
401  
    {
402  
    {
402  
        return impl_.measure(
403  
        return impl_.measure(
403  
            static_cast<base_value_type>(v), ctx, cs);
404  
            static_cast<base_value_type>(v), ctx, cs);
404  
    }
405  
    }
405  

406  

406  
    char*
407  
    char*
407  
    format(T v, format_context& ctx, grammar::lut_chars const& cs) const
408  
    format(T v, format_context& ctx, grammar::lut_chars const& cs) const
408  
    {
409  
    {
409  
        return impl_.format(
410  
        return impl_.format(
410  
            static_cast<base_value_type>(v), ctx, cs);
411  
            static_cast<base_value_type>(v), ctx, cs);
411  
    }
412  
    }
412  
};
413  
};
413  

414  

414  
} // detail
415  
} // detail
415  
} // url
416  
} // url
416  
} // boost
417  
} // boost
417  

418  

418  
#endif
419  
#endif