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_FORMAT_ARGS_HPP
10  
#ifndef BOOST_URL_DETAIL_FORMAT_ARGS_HPP
11  
#define BOOST_URL_DETAIL_FORMAT_ARGS_HPP
11  
#define BOOST_URL_DETAIL_FORMAT_ARGS_HPP
12  

12  

13  
#include <boost/url/detail/encode.hpp>
13  
#include <boost/url/detail/encode.hpp>
14  
#include <boost/url/grammar/lut_chars.hpp>
14  
#include <boost/url/grammar/lut_chars.hpp>
15  

15  

16  
#include <boost/core/ignore_unused.hpp>
16  
#include <boost/core/ignore_unused.hpp>
17  
#include <array>
17  
#include <array>
18  

18  

19  
// This file implements functions and classes to
19  
// This file implements functions and classes to
20  
// type-erase format arguments.
20  
// type-erase format arguments.
21  

21  

22  
namespace boost {
22  
namespace boost {
23  
namespace urls {
23  
namespace urls {
24  
namespace detail {
24  
namespace detail {
25  

25  

26  
// state of the format string. It basically keeps
26  
// state of the format string. It basically keeps
27  
// track of where we are in the format string.
27  
// track of where we are in the format string.
28  
class format_parse_context
28  
class format_parse_context
29  
{
29  
{
30  
    char const* begin_;
30  
    char const* begin_;
31  
    char const* end_;
31  
    char const* end_;
32  
    std::size_t arg_id_ = 0;
32  
    std::size_t arg_id_ = 0;
33  

33  

34  
public:
34  
public:
35  
    constexpr
35  
    constexpr
36  
    format_parse_context(
36  
    format_parse_context(
37  
        char const* first,
37  
        char const* first,
38  
        char const* last,
38  
        char const* last,
39  
        std::size_t arg_id = 0)
39  
        std::size_t arg_id = 0)
40  
        : begin_( first )
40  
        : begin_( first )
41  
        , end_( last )
41  
        , end_( last )
42  
        , arg_id_( arg_id )
42  
        , arg_id_( arg_id )
43  
    {}
43  
    {}
44  

44  

45  
    constexpr
45  
    constexpr
46  
    format_parse_context(
46  
    format_parse_context(
47  
        core::string_view fmt,
47  
        core::string_view fmt,
48  
        std::size_t arg_id = 0)
48  
        std::size_t arg_id = 0)
49  
        : format_parse_context(
49  
        : format_parse_context(
50  
            fmt.data(),
50  
            fmt.data(),
51  
            fmt.data() + fmt.size(),
51  
            fmt.data() + fmt.size(),
52  
            arg_id )
52  
            arg_id )
53  
    {}
53  
    {}
54  

54  

55  
    constexpr
55  
    constexpr
56  
    char const*
56  
    char const*
57  
    begin() const noexcept
57  
    begin() const noexcept
58  
    {
58  
    {
59  
        return begin_;
59  
        return begin_;
60  
    }
60  
    }
61  

61  

62  
    constexpr
62  
    constexpr
63  
    char const*
63  
    char const*
64  
    end() const noexcept
64  
    end() const noexcept
65  
    {
65  
    {
66  
        return end_;
66  
        return end_;
67  
    }
67  
    }
68  

68  

69  
    BOOST_CXX14_CONSTEXPR
69  
    BOOST_CXX14_CONSTEXPR
70  
    void
70  
    void
71  
    advance_to( char const* it )
71  
    advance_to( char const* it )
72  
    {
72  
    {
73  
        begin_ = it;
73  
        begin_ = it;
74  
    }
74  
    }
75  

75  

76  
    std::size_t
76  
    std::size_t
77  
    next_arg_id()
77  
    next_arg_id()
78  
    {
78  
    {
79  
        return arg_id_++;
79  
        return arg_id_++;
80  
    }
80  
    }
81  
};
81  
};
82  

82  

83  
// State of the destination string
83  
// State of the destination string
84  
class format_context;
84  
class format_context;
85  
class measure_context;
85  
class measure_context;
86  
struct ignore_format {};
86  
struct ignore_format {};
87  

87  

88  
template <class T>
88  
template <class T>
89  
struct named_arg
89  
struct named_arg
90  
{
90  
{
91  
    core::string_view name;
91  
    core::string_view name;
92  
    T const& value;
92  
    T const& value;
93  

93  

94  
    named_arg(core::string_view n, T const& v)
94  
    named_arg(core::string_view n, T const& v)
95  
        : name(n)
95  
        : name(n)
96  
        , value(v)
96  
        , value(v)
97  
    {}
97  
    {}
98  
};
98  
};
99  

99  

100  
// A type erased format argument
100  
// A type erased format argument
101  
class format_arg
101  
class format_arg
102  
{
102  
{
103  
    void const* arg_;
103  
    void const* arg_;
104  
    void (*measure_)(
104  
    void (*measure_)(
105  
        format_parse_context&,
105  
        format_parse_context&,
106  
        measure_context&,
106  
        measure_context&,
107  
        grammar::lut_chars const&,
107  
        grammar::lut_chars const&,
108  
        void const* );
108  
        void const* );
109  
    void (*fmt_)(
109  
    void (*fmt_)(
110  
        format_parse_context&,
110  
        format_parse_context&,
111  
        format_context&,
111  
        format_context&,
112  
        grammar::lut_chars const&,
112  
        grammar::lut_chars const&,
113  
        void const* );
113  
        void const* );
114  
    core::string_view name_;
114  
    core::string_view name_;
115  
    std::size_t value_ = 0;
115  
    std::size_t value_ = 0;
116  
    bool ignore_ = false;
116  
    bool ignore_ = false;
117  

117  

118  
    template <class A>
118  
    template <class A>
119  
    static
119  
    static
120  
    void
120  
    void
121  
    measure_impl(
121  
    measure_impl(
122  
        format_parse_context& pctx,
122  
        format_parse_context& pctx,
123  
        measure_context& mctx,
123  
        measure_context& mctx,
124  
        grammar::lut_chars const& cs,
124  
        grammar::lut_chars const& cs,
125  
        void const* a );
125  
        void const* a );
126  

126  

127  
    template <class A>
127  
    template <class A>
128  
    static
128  
    static
129  
    void
129  
    void
130  
    format_impl(
130  
    format_impl(
131  
        format_parse_context& pctx,
131  
        format_parse_context& pctx,
132  
        format_context& fctx,
132  
        format_context& fctx,
133  
        grammar::lut_chars const& cs,
133  
        grammar::lut_chars const& cs,
134  
        void const* a );
134  
        void const* a );
135  

135  

136  
public:
136  
public:
137  
    template<class A>
137  
    template<class A>
138  
    format_arg( A&& a );
138  
    format_arg( A&& a );
139  

139  

140  
    template<class A>
140  
    template<class A>
141  
    format_arg( named_arg<A>&& a );
141  
    format_arg( named_arg<A>&& a );
142  

142  

143  
    template<class A>
143  
    template<class A>
144  
    format_arg( core::string_view name, A&& a );
144  
    format_arg( core::string_view name, A&& a );
145  

145  

146  
    format_arg()
146  
    format_arg()
147  
        : format_arg(ignore_format{})
147  
        : format_arg(ignore_format{})
148  
    {}
148  
    {}
149  

149  

150  
    explicit
150  
    explicit
151  
    operator bool() const noexcept
151  
    operator bool() const noexcept
152  
    {
152  
    {
153  
        return !ignore_;
153  
        return !ignore_;
154  
    }
154  
    }
155  

155  

156  
    void
156  
    void
157  
    measure(
157  
    measure(
158  
        format_parse_context& pctx,
158  
        format_parse_context& pctx,
159  
        measure_context& mctx,
159  
        measure_context& mctx,
160  
        grammar::lut_chars const& cs)
160  
        grammar::lut_chars const& cs)
161  
    {
161  
    {
162  
        measure_( pctx, mctx, cs, arg_ );
162  
        measure_( pctx, mctx, cs, arg_ );
163  
    }
163  
    }
164  

164  

165  
    void
165  
    void
166  
    format(
166  
    format(
167  
        format_parse_context& pctx,
167  
        format_parse_context& pctx,
168  
        format_context& fctx,
168  
        format_context& fctx,
169  
        grammar::lut_chars const& cs )
169  
        grammar::lut_chars const& cs )
170  
    {
170  
    {
171  
        fmt_( pctx, fctx, cs, arg_ );
171  
        fmt_( pctx, fctx, cs, arg_ );
172  
    }
172  
    }
173  

173  

174  
    core::string_view
174  
    core::string_view
175  
    name() const
175  
    name() const
176  
    {
176  
    {
177  
        return name_;
177  
        return name_;
178  
    }
178  
    }
179  

179  

180  
    std::size_t
180  
    std::size_t
181  
    value() const
181  
    value() const
182  
    {
182  
    {
183  
        return value_;
183  
        return value_;
184  
    }
184  
    }
185  
};
185  
};
186  

186  

187  
// create temp stack storage for type erased args
187  
// create temp stack storage for type erased args
188  
template< class... Args >
188  
template< class... Args >
189  
std::array<format_arg, sizeof...(Args)>
189  
std::array<format_arg, sizeof...(Args)>
190  
make_format_args( Args&&... args )
190  
make_format_args( Args&&... args )
191  
{
191  
{
192  
    return {{ std::forward<Args>(args)... }};
192  
    return {{ std::forward<Args>(args)... }};
193  
}
193  
}
194  

194  

195  
// reference to an array of format_args
195  
// reference to an array of format_args
196  
class format_args
196  
class format_args
197  
{
197  
{
198  
    format_arg const* p_{nullptr};
198  
    format_arg const* p_{nullptr};
199  
    std::size_t n_{0};
199  
    std::size_t n_{0};
200  

200  

201  
public:
201  
public:
202  
    format_args(
202  
    format_args(
203  
        detail::format_arg const* first,
203  
        detail::format_arg const* first,
204  
        detail::format_arg const* last ) noexcept
204  
        detail::format_arg const* last ) noexcept
205  
        : p_(first)
205  
        : p_(first)
206  
        , n_(static_cast<std::size_t>(last - first))
206  
        , n_(static_cast<std::size_t>(last - first))
207  
    {}
207  
    {}
208  

208  

209  
    template < std::size_t N >
209  
    template < std::size_t N >
210  
    format_args( std::array<format_arg, N> const& store ) noexcept
210  
    format_args( std::array<format_arg, N> const& store ) noexcept
211  
        : p_(store.data())
211  
        : p_(store.data())
212  
        , n_(store.size())
212  
        , n_(store.size())
213  
    {}
213  
    {}
214  

214  

215  
    format_arg
215  
    format_arg
216  
    get( std::size_t i ) const noexcept
216  
    get( std::size_t i ) const noexcept
217  
    {
217  
    {
218  
        if (i < n_)
218  
        if (i < n_)
219  
            return p_[i];
219  
            return p_[i];
220  
        return {};
220  
        return {};
221  
    }
221  
    }
222  

222  

223  
    format_arg
223  
    format_arg
224  
    get( core::string_view name ) const noexcept
224  
    get( core::string_view name ) const noexcept
225  
    {
225  
    {
226  
        for (std::size_t i = 0; i < n_; ++i)
226  
        for (std::size_t i = 0; i < n_; ++i)
227  
        {
227  
        {
228  
            if (p_[i].name() == name)
228  
            if (p_[i].name() == name)
229  
                return p_[i];
229  
                return p_[i];
230  
        }
230  
        }
231  
        return {};
231  
        return {};
232  
    }
232  
    }
233  
};
233  
};
234  

234  

235  
// define the format_context after format_args
235  
// define the format_context after format_args
236  
class format_context
236  
class format_context
237  
{
237  
{
238  
    format_args args_;
238  
    format_args args_;
239  
    char* out_;
239  
    char* out_;
240  

240  

241  
public:
241  
public:
242  
    format_context(
242  
    format_context(
243  
        char* out,
243  
        char* out,
244  
        format_args args )
244  
        format_args args )
245  
        : args_( args )
245  
        : args_( args )
246  
        , out_( out )
246  
        , out_( out )
247  
    {}
247  
    {}
248  

248  

249  
    format_args
249  
    format_args
250  
    args() const noexcept
250  
    args() const noexcept
251  
    {
251  
    {
252  
        return args_;
252  
        return args_;
253  
    }
253  
    }
254  

254  

255  
    format_arg
255  
    format_arg
256  
    arg( std::size_t id ) const noexcept
256  
    arg( std::size_t id ) const noexcept
257  
    {
257  
    {
258  
        return args_.get( id );
258  
        return args_.get( id );
259  
    }
259  
    }
260  

260  

261  
    format_arg
261  
    format_arg
262  
    arg( core::string_view name ) const noexcept
262  
    arg( core::string_view name ) const noexcept
263  
    {
263  
    {
264  
        return args_.get( name );
264  
        return args_.get( name );
265  
    }
265  
    }
266  

266  

267  
    char*
267  
    char*
268  
    out()
268  
    out()
269  
    {
269  
    {
270  
        return out_;
270  
        return out_;
271  
    }
271  
    }
272  

272  

273  
    void
273  
    void
274  
    advance_to( char* it )
274  
    advance_to( char* it )
275  
    {
275  
    {
276  
        out_ = it;
276  
        out_ = it;
277  
    }
277  
    }
278  
};
278  
};
279  

279  

280  
// define the measure_context after format_args
280  
// define the measure_context after format_args
281  
class measure_context
281  
class measure_context
282  
{
282  
{
283  
    format_args args_;
283  
    format_args args_;
284  
    std::size_t out_;
284  
    std::size_t out_;
285  

285  

286  
public:
286  
public:
287  
    measure_context(
287  
    measure_context(
288  
        format_args args )
288  
        format_args args )
289  
        : measure_context(0, args)
289  
        : measure_context(0, args)
290  
    {}
290  
    {}
291  

291  

292  
    measure_context(
292  
    measure_context(
293  
        std::size_t out,
293  
        std::size_t out,
294  
        format_args args )
294  
        format_args args )
295  
        : args_( args )
295  
        : args_( args )
296  
        , out_( out )
296  
        , out_( out )
297  
    {}
297  
    {}
298  

298  

299  
    format_args
299  
    format_args
300  
    args() const noexcept
300  
    args() const noexcept
301  
    {
301  
    {
302  
        return args_;
302  
        return args_;
303  
    }
303  
    }
304  

304  

305  
    format_arg
305  
    format_arg
306  
    arg( std::size_t id ) const noexcept
306  
    arg( std::size_t id ) const noexcept
307  
    {
307  
    {
308  
        return args_.get( id );
308  
        return args_.get( id );
309  
    }
309  
    }
310  

310  

311  
    format_arg
311  
    format_arg
312  
    arg( core::string_view name ) const noexcept
312  
    arg( core::string_view name ) const noexcept
313  
    {
313  
    {
314  
        return args_.get( name );
314  
        return args_.get( name );
315  
    }
315  
    }
316  

316  

317  
    std::size_t
317  
    std::size_t
318  
    out()
318  
    out()
319  
    {
319  
    {
320  
        return out_;
320  
        return out_;
321  
    }
321  
    }
322  

322  

323  
    void
323  
    void
324  
    advance_to( std::size_t n )
324  
    advance_to( std::size_t n )
325  
    {
325  
    {
326  
        out_ = n;
326  
        out_ = n;
327  
    }
327  
    }
328  
};
328  
};
329  

329  

330  
// fwd declare the formatter
330  
// fwd declare the formatter
331  
template <class T, class = void>
331  
template <class T, class = void>
332  
struct formatter;
332  
struct formatter;
333  

333  

334  
} // detail
334  
} // detail
335  
} // url
335  
} // url
336  
} // boost
336  
} // boost
337  

337  

338  
#include <boost/url/detail/impl/format_args.hpp>
338  
#include <boost/url/detail/impl/format_args.hpp>
339  

339  

340  
#endif
340  
#endif