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  
    *out++ = urls::detail::hexdigs[0][c>>4];
216  
    *out++ = urls::detail::hexdigs[0][c&0xf];
216  
    *out++ = urls::detail::hexdigs[0][c&0xf];
217  
}
217  
}
218  

218  

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

227  

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

238  

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

243  

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

250  

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

258  

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

268  

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

275  

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

284  

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

291  

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

296  

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

303  

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

312  

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

322  

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

333  

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

338  

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

345  

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

352  

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

359  

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

367  

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

388  

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

395  

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

405  

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

413  

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

417  

418  
#endif
418  
#endif