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  

10  

11  
#include <boost/url/detail/config.hpp>
11  
#include <boost/url/detail/config.hpp>
12  
#include <boost/url/encode.hpp>
12  
#include <boost/url/encode.hpp>
13  
#include <boost/url/detail/format_args.hpp>
13  
#include <boost/url/detail/format_args.hpp>
14  
#include "boost/url/detail/replacement_field_rule.hpp"
14  
#include "boost/url/detail/replacement_field_rule.hpp"
15  
#include <boost/url/grammar/delim_rule.hpp>
15  
#include <boost/url/grammar/delim_rule.hpp>
16  
#include <boost/url/grammar/optional_rule.hpp>
16  
#include <boost/url/grammar/optional_rule.hpp>
17  
#include <boost/url/grammar/parse.hpp>
17  
#include <boost/url/grammar/parse.hpp>
18  
#include <boost/url/grammar/tuple_rule.hpp>
18  
#include <boost/url/grammar/tuple_rule.hpp>
19  
#include <boost/url/grammar/unsigned_rule.hpp>
19  
#include <boost/url/grammar/unsigned_rule.hpp>
20  

20  

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

24  

25  
std::size_t
25  
std::size_t
26  
get_uvalue( core::string_view a )
26  
get_uvalue( core::string_view a )
27  
{
27  
{
28  
    core::string_view str(a);
28  
    core::string_view str(a);
29  
    auto rv = grammar::parse(
29  
    auto rv = grammar::parse(
30  
        str, grammar::unsigned_rule<std::size_t>{});
30  
        str, grammar::unsigned_rule<std::size_t>{});
31  
    if (rv)
31  
    if (rv)
32  
        return *rv;
32  
        return *rv;
33  
    return 0;
33  
    return 0;
34  
}
34  
}
35  

35  

36  
std::size_t
36  
std::size_t
37  
get_uvalue( char a )
37  
get_uvalue( char a )
38  
{
38  
{
39  
    core::string_view str(&a, 1);
39  
    core::string_view str(&a, 1);
40  
    return get_uvalue(str);
40  
    return get_uvalue(str);
41  
}
41  
}
42  

42  

43  
char const*
43  
char const*
44  
formatter<core::string_view>::
44  
formatter<core::string_view>::
45  
parse(format_parse_context& ctx)
45  
parse(format_parse_context& ctx)
46  
{
46  
{
47  
    char const* it = ctx.begin();
47  
    char const* it = ctx.begin();
48  
    char const* end = ctx.end();
48  
    char const* end = ctx.end();
49  
    BOOST_ASSERT(it != end);
49  
    BOOST_ASSERT(it != end);
50  

50  

51  
    // fill / align
51  
    // fill / align
52  
    if (end - it > 2)
52  
    if (end - it > 2)
53  
    {
53  
    {
54  
        if (*it != '{' &&
54  
        if (*it != '{' &&
55  
            *it != '}' &&
55  
            *it != '}' &&
56  
            (*(it + 1) == '<' ||
56  
            (*(it + 1) == '<' ||
57  
             *(it + 1) == '>' ||
57  
             *(it + 1) == '>' ||
58  
             *(it + 1) == '^'))
58  
             *(it + 1) == '^'))
59  
        {
59  
        {
60  
            fill = *it;
60  
            fill = *it;
61  
            align = *(it + 1);
61  
            align = *(it + 1);
62  
            it += 2;
62  
            it += 2;
63  
        }
63  
        }
64  
    }
64  
    }
65  

65  

66  
    // align
66  
    // align
67  
    if (align == '\0' &&
67  
    if (align == '\0' &&
68  
        (*it == '<' ||
68  
        (*it == '<' ||
69  
         *it == '>' ||
69  
         *it == '>' ||
70  
         *it == '^'))
70  
         *it == '^'))
71  
    {
71  
    {
72  
        align = *it++;
72  
        align = *it++;
73  
    }
73  
    }
74  

74  

75  
    // width
75  
    // width
76  
    char const* it0 = it;
76  
    char const* it0 = it;
77  
    constexpr auto width_rule =
77  
    constexpr auto width_rule =
78  
        grammar::variant_rule(
78  
        grammar::variant_rule(
79  
             grammar::unsigned_rule<std::size_t>{},
79  
             grammar::unsigned_rule<std::size_t>{},
80  
             grammar::tuple_rule(
80  
             grammar::tuple_rule(
81  
                 grammar::squelch(
81  
                 grammar::squelch(
82  
                     grammar::delim_rule('{')),
82  
                     grammar::delim_rule('{')),
83  
                 grammar::optional_rule(
83  
                 grammar::optional_rule(
84  
                    arg_id_rule),
84  
                    arg_id_rule),
85  
                 grammar::squelch(
85  
                 grammar::squelch(
86  
                     grammar::delim_rule('}'))));
86  
                     grammar::delim_rule('}'))));
87  
    auto rw = grammar::parse(it, end, width_rule);
87  
    auto rw = grammar::parse(it, end, width_rule);
88  
    if (!rw)
88  
    if (!rw)
89  
    {
89  
    {
90  
        // rewind
90  
        // rewind
91  
        it = it0;
91  
        it = it0;
92  
    }
92  
    }
93  
    else if (align != '\0')
93  
    else if (align != '\0')
94  
    {
94  
    {
95  
        // width is ignored when align is '\0'
95  
        // width is ignored when align is '\0'
96  
        if (rw->index() == 0)
96  
        if (rw->index() == 0)
97  
        {
97  
        {
98  
            // unsigned_rule
98  
            // unsigned_rule
99  
            width = variant2::get<0>(*rw);
99  
            width = variant2::get<0>(*rw);
100  
        }
100  
        }
101  
        else
101  
        else
102  
        {
102  
        {
103  
            // arg_id: store the id idx or string
103  
            // arg_id: store the id idx or string
104  
            auto& arg_id = variant2::get<1>(*rw);
104  
            auto& arg_id = variant2::get<1>(*rw);
105  
            if (!arg_id)
105  
            if (!arg_id)
106  
            {
106  
            {
107  
                // empty arg_id, use and consume
107  
                // empty arg_id, use and consume
108  
                // the next arg idx
108  
                // the next arg idx
109  
                width_idx = ctx.next_arg_id();
109  
                width_idx = ctx.next_arg_id();
110  
            }
110  
            }
111  
            else if (arg_id->index() == 0)
111  
            else if (arg_id->index() == 0)
112  
            {
112  
            {
113  
                // string identifier
113  
                // string identifier
114  
                width_name = variant2::get<0>(*arg_id);
114  
                width_name = variant2::get<0>(*arg_id);
115  
            }
115  
            }
116  
            else
116  
            else
117  
            {
117  
            {
118  
                // integer identifier: use the
118  
                // integer identifier: use the
119  
                // idx of this format_arg
119  
                // idx of this format_arg
120  
                width_idx = variant2::get<1>(*arg_id);
120  
                width_idx = variant2::get<1>(*arg_id);
121  
            }
121  
            }
122  
        }
122  
        }
123  
    }
123  
    }
124  

124  

125  
    // type is parsed but doesn't have to
125  
    // type is parsed but doesn't have to
126  
    // be stored for strings
126  
    // be stored for strings
127  
    if (*it == 'c' ||
127  
    if (*it == 'c' ||
128  
        *it == 's')
128  
        *it == 's')
129  
    {
129  
    {
130  
        ++it;
130  
        ++it;
131  
    }
131  
    }
132  

132  

133  
    // we should have arrived at the end now
133  
    // we should have arrived at the end now
134  
    if (*it != '}')
134  
    if (*it != '}')
135  
    {
135  
    {
136  
        urls::detail::throw_invalid_argument();
136  
        urls::detail::throw_invalid_argument();
137  
    }
137  
    }
138  

138  

139  
    return it;
139  
    return it;
140  
}
140  
}
141  

141  

142  
std::size_t
142  
std::size_t
143  
formatter<core::string_view>::
143  
formatter<core::string_view>::
144  
measure(
144  
measure(
145  
    core::string_view str,
145  
    core::string_view str,
146  
    measure_context& ctx,
146  
    measure_context& ctx,
147  
    grammar::lut_chars const& cs) const
147  
    grammar::lut_chars const& cs) const
148  
{
148  
{
149  
    std::size_t w = width;
149  
    std::size_t w = width;
150  
    if (width_idx != std::size_t(-1) ||
150  
    if (width_idx != std::size_t(-1) ||
151  
        !width_name.empty())
151  
        !width_name.empty())
152  
    {
152  
    {
153  
        get_width_from_args(
153  
        get_width_from_args(
154  
            width_idx, width_name, ctx.args(), w);
154  
            width_idx, width_name, ctx.args(), w);
155  
    }
155  
    }
156  

156  

157  
    std::size_t n = ctx.out();
157  
    std::size_t n = ctx.out();
158  
    if (str.size() < w)
158  
    if (str.size() < w)
159  
        n += measure_one(fill, cs) * (w - str.size());
159  
        n += measure_one(fill, cs) * (w - str.size());
160  

160  

161  
    return n + encoded_size(str, cs);
161  
    return n + encoded_size(str, cs);
162  
}
162  
}
163  

163  

164  
char*
164  
char*
165  
formatter<core::string_view>::
165  
formatter<core::string_view>::
166  
format(core::string_view str, format_context& ctx, grammar::lut_chars const& cs) const
166  
format(core::string_view str, format_context& ctx, grammar::lut_chars const& cs) const
167  
{
167  
{
168  
    std::size_t w = width;
168  
    std::size_t w = width;
169  
    if (width_idx != std::size_t(-1) ||
169  
    if (width_idx != std::size_t(-1) ||
170  
        !width_name.empty())
170  
        !width_name.empty())
171  
    {
171  
    {
172  
        get_width_from_args(
172  
        get_width_from_args(
173  
            width_idx, width_name, ctx.args(), w);
173  
            width_idx, width_name, ctx.args(), w);
174  
    }
174  
    }
175  

175  

176  
    std::size_t lpad = 0;
176  
    std::size_t lpad = 0;
177  
    std::size_t rpad = 0;
177  
    std::size_t rpad = 0;
178  
    if (str.size() < w)
178  
    if (str.size() < w)
179  
    {
179  
    {
180  
        std::size_t pad = w - str.size();
180  
        std::size_t pad = w - str.size();
181  
        switch (align)
181  
        switch (align)
182  
        {
182  
        {
183  
        case '<':
183  
        case '<':
184  
            rpad = pad;
184  
            rpad = pad;
185  
            break;
185  
            break;
186  
        case '>':
186  
        case '>':
187  
            lpad = pad;
187  
            lpad = pad;
188  
            break;
188  
            break;
189  
        case '^':
189  
        case '^':
190  
            lpad = w / 2;
190  
            lpad = w / 2;
191  
            rpad = pad - lpad;
191  
            rpad = pad - lpad;
192  
            break;
192  
            break;
193  
        }
193  
        }
194  
    }
194  
    }
195  

195  

196  
    // unsafe `encode`, assuming `out` has
196  
    // unsafe `encode`, assuming `out` has
197  
    // enough capacity
197  
    // enough capacity
198  
    char* out = ctx.out();
198  
    char* out = ctx.out();
199  
    for (std::size_t i = 0; i < lpad; ++i)
199  
    for (std::size_t i = 0; i < lpad; ++i)
200  
        encode_one(out, fill, cs);
200  
        encode_one(out, fill, cs);
201  
    for (char c: str)
201  
    for (char c: str)
202  
        encode_one(out, c, cs);
202  
        encode_one(out, c, cs);
203  
    for (std::size_t i = 0; i < rpad; ++i)
203  
    for (std::size_t i = 0; i < rpad; ++i)
204  
        encode_one(out, fill, cs);
204  
        encode_one(out, fill, cs);
205  
    return out;
205  
    return out;
206  
}
206  
}
207  

207  

208  
void
208  
void
209  
get_width_from_args(
209  
get_width_from_args(
210  
    std::size_t arg_idx,
210  
    std::size_t arg_idx,
211  
    core::string_view arg_name,
211  
    core::string_view arg_name,
212  
    format_args args,
212  
    format_args args,
213  
    std::size_t& w)
213  
    std::size_t& w)
214  
{
214  
{
215  
    // check arg_id
215  
    // check arg_id
216  
    format_arg warg;
216  
    format_arg warg;
217  
    if (arg_idx != std::size_t(-1))
217  
    if (arg_idx != std::size_t(-1))
218  
    {
218  
    {
219  
        // identifier
219  
        // identifier
220  
        warg = args.get(arg_idx);
220  
        warg = args.get(arg_idx);
221  
    }
221  
    }
222  
    else
222  
    else
223  
    {
223  
    {
224  
        // unsigned integer
224  
        // unsigned integer
225  
        warg = args.get(arg_name);
225  
        warg = args.get(arg_name);
226  
    }
226  
    }
227  

227  

228  
    // get unsigned int value from that format arg
228  
    // get unsigned int value from that format arg
229  
    w = warg.value();
229  
    w = warg.value();
230  
}
230  
}
231  

231  

232  
char const*
232  
char const*
233  
integer_formatter_impl::
233  
integer_formatter_impl::
234  
parse(format_parse_context& ctx)
234  
parse(format_parse_context& ctx)
235  
{
235  
{
236  
    char const* it = ctx.begin();
236  
    char const* it = ctx.begin();
237  
    char const* end = ctx.end();
237  
    char const* end = ctx.end();
238  
    BOOST_ASSERT(it != end);
238  
    BOOST_ASSERT(it != end);
239  

239  

240  
    // fill / align
240  
    // fill / align
241  
    if (end - it > 2)
241  
    if (end - it > 2)
242  
    {
242  
    {
243  
        if (*it != '{' &&
243  
        if (*it != '{' &&
244  
            *it != '}' &&
244  
            *it != '}' &&
245  
            (*(it + 1) == '<' ||
245  
            (*(it + 1) == '<' ||
246  
             *(it + 1) == '>' ||
246  
             *(it + 1) == '>' ||
247  
             *(it + 1) == '^'))
247  
             *(it + 1) == '^'))
248  
        {
248  
        {
249  
            fill = *it;
249  
            fill = *it;
250  
            align = *(it + 1);
250  
            align = *(it + 1);
251  
            it += 2;
251  
            it += 2;
252  
        }
252  
        }
253  
    }
253  
    }
254  

254  

255  
    // align
255  
    // align
256  
    if (align == '\0' &&
256  
    if (align == '\0' &&
257  
        (*it == '<' ||
257  
        (*it == '<' ||
258  
         *it == '>' ||
258  
         *it == '>' ||
259  
         *it == '^'))
259  
         *it == '^'))
260  
    {
260  
    {
261  
        align = *it++;
261  
        align = *it++;
262  
    }
262  
    }
263  

263  

264  
    // sign
264  
    // sign
265  
    if (*it == '+' ||
265  
    if (*it == '+' ||
266  
        *it == '-' ||
266  
        *it == '-' ||
267  
        *it == ' ')
267  
        *it == ' ')
268  
    {
268  
    {
269  
        sign = *it++;
269  
        sign = *it++;
270  
    }
270  
    }
271  

271  

272  
    // #
272  
    // #
273  
    if (*it == '#')
273  
    if (*it == '#')
274  
    {
274  
    {
275  
        // alternate form not supported
275  
        // alternate form not supported
276  
        ++it;
276  
        ++it;
277  
    }
277  
    }
278  

278  

279  
    // 0
279  
    // 0
280  
    if (*it == '0')
280  
    if (*it == '0')
281  
    {
281  
    {
282  
        zeros = *it++;
282  
        zeros = *it++;
283  
    }
283  
    }
284  

284  

285  
    // width
285  
    // width
286  
    char const* it0 = it;
286  
    char const* it0 = it;
287  
    constexpr auto width_rule = grammar::variant_rule(
287  
    constexpr auto width_rule = grammar::variant_rule(
288  
        grammar::unsigned_rule<std::size_t>{},
288  
        grammar::unsigned_rule<std::size_t>{},
289  
        grammar::tuple_rule(
289  
        grammar::tuple_rule(
290  
            grammar::squelch(
290  
            grammar::squelch(
291  
                grammar::delim_rule('{')),
291  
                grammar::delim_rule('{')),
292  
            grammar::optional_rule(
292  
            grammar::optional_rule(
293  
                arg_id_rule),
293  
                arg_id_rule),
294  
            grammar::squelch(
294  
            grammar::squelch(
295  
                grammar::delim_rule('}'))));
295  
                grammar::delim_rule('}'))));
296  
    auto rw = grammar::parse(it, end, width_rule);
296  
    auto rw = grammar::parse(it, end, width_rule);
297  
    if (!rw)
297  
    if (!rw)
298  
    {
298  
    {
299  
        // rewind
299  
        // rewind
300  
        it = it0;
300  
        it = it0;
301  
    }
301  
    }
302  
    else if (align != '\0')
302  
    else if (align != '\0')
303  
    {
303  
    {
304  
        // width is ignored when align is '\0'
304  
        // width is ignored when align is '\0'
305  
        if (rw->index() == 0)
305  
        if (rw->index() == 0)
306  
        {
306  
        {
307  
            // unsigned_rule
307  
            // unsigned_rule
308  
            width = variant2::get<0>(*rw);
308  
            width = variant2::get<0>(*rw);
309  
        }
309  
        }
310  
        else
310  
        else
311  
        {
311  
        {
312  
            // arg_id: store the id idx or string
312  
            // arg_id: store the id idx or string
313  
            auto& arg_id = variant2::get<1>(*rw);
313  
            auto& arg_id = variant2::get<1>(*rw);
314  
            if (!arg_id)
314  
            if (!arg_id)
315  
            {
315  
            {
316  
                // empty arg_id, use and consume
316  
                // empty arg_id, use and consume
317  
                // the next arg idx
317  
                // the next arg idx
318  
                width_idx = ctx.next_arg_id();
318  
                width_idx = ctx.next_arg_id();
319  
            }
319  
            }
320  
            else if (arg_id->index() == 0)
320  
            else if (arg_id->index() == 0)
321  
            {
321  
            {
322  
                // string identifier
322  
                // string identifier
323  
                width_name = variant2::get<0>(*arg_id);
323  
                width_name = variant2::get<0>(*arg_id);
324  
            }
324  
            }
325  
            else
325  
            else
326  
            {
326  
            {
327  
                // integer identifier: use the
327  
                // integer identifier: use the
328  
                // idx of this format_arg
328  
                // idx of this format_arg
329  
                width_idx = variant2::get<1>(*arg_id);
329  
                width_idx = variant2::get<1>(*arg_id);
330  
            }
330  
            }
331  
        }
331  
        }
332  
    }
332  
    }
333  

333  

334  
    // type is parsed but doesn't have to
334  
    // type is parsed but doesn't have to
335  
    // be stored for strings
335  
    // be stored for strings
336  
    if (*it == 'd')
336  
    if (*it == 'd')
337  
    {
337  
    {
338  
        // we don't include other presentation
338  
        // we don't include other presentation
339  
        // modes for integers as they are not
339  
        // modes for integers as they are not
340  
        // recommended or generally used in
340  
        // recommended or generally used in
341  
        // urls
341  
        // urls
342  
        ++it;
342  
        ++it;
343  
    }
343  
    }
344  

344  

345  
    // we should have arrived at the end now
345  
    // we should have arrived at the end now
346  
    if (*it != '}')
346  
    if (*it != '}')
347  
    {
347  
    {
348  
        urls::detail::throw_invalid_argument();
348  
        urls::detail::throw_invalid_argument();
349  
    }
349  
    }
350  

350  

351  
    return it;
351  
    return it;
352  
}
352  
}
353  

353  

354  
std::size_t
354  
std::size_t
355  
integer_formatter_impl::
355  
integer_formatter_impl::
356  
measure(
356  
measure(
357  
    long long int v,
357  
    long long int v,
358  
    measure_context& ctx,
358  
    measure_context& ctx,
359  
    grammar::lut_chars const& cs) const
359  
    grammar::lut_chars const& cs) const
360  
{
360  
{
361  
    std::size_t dn = 0;
361  
    std::size_t dn = 0;
362  
    std::size_t n = 0;
362  
    std::size_t n = 0;
363  
    if (v < 0)
363  
    if (v < 0)
364  
    {
364  
    {
365  
        dn += measure_one('-', cs);
365  
        dn += measure_one('-', cs);
366  
        ++n;
366  
        ++n;
367  
        v *= -1;
367  
        v *= -1;
368  
    }
368  
    }
369  
    else if (sign != '-')
369  
    else if (sign != '-')
370  
    {
370  
    {
371  
        dn += measure_one(sign, cs);
371  
        dn += measure_one(sign, cs);
372  
        ++n;
372  
        ++n;
373  
    }
373  
    }
374  
    do
374  
    do
375  
    {
375  
    {
376  
        int d = v % 10;
376  
        int d = v % 10;
377  
        v /= 10;
377  
        v /= 10;
378  
        dn += measure_one('0' + static_cast<char>(d), cs);
378  
        dn += measure_one('0' + static_cast<char>(d), cs);
379  
        ++n;
379  
        ++n;
380  
    }
380  
    }
381  
    while (v > 0);
381  
    while (v > 0);
382  

382  

383  
    std::size_t w = width;
383  
    std::size_t w = width;
384  
    if (width_idx != std::size_t(-1) ||
384  
    if (width_idx != std::size_t(-1) ||
385  
        !width_name.empty())
385  
        !width_name.empty())
386  
    {
386  
    {
387  
        get_width_from_args(
387  
        get_width_from_args(
388  
            width_idx, width_name, ctx.args(), w);
388  
            width_idx, width_name, ctx.args(), w);
389  
    }
389  
    }
390  
    if (w > n)
390  
    if (w > n)
391  
    {
391  
    {
392  
        if (!zeros)
392  
        if (!zeros)
393  
            dn += measure_one(fill, cs) * (w - n);
393  
            dn += measure_one(fill, cs) * (w - n);
394  
        else
394  
        else
395  
            dn += measure_one('0', cs) * (w - n);
395  
            dn += measure_one('0', cs) * (w - n);
396  
    }
396  
    }
397  
    return ctx.out() + dn;
397  
    return ctx.out() + dn;
398  
}
398  
}
399  

399  

400  
std::size_t
400  
std::size_t
401  
integer_formatter_impl::
401  
integer_formatter_impl::
402  
measure(
402  
measure(
403  
    unsigned long long int v,
403  
    unsigned long long int v,
404  
    measure_context& ctx,
404  
    measure_context& ctx,
405  
    grammar::lut_chars const& cs) const
405  
    grammar::lut_chars const& cs) const
406  
{
406  
{
407  
    std::size_t dn = 0;
407  
    std::size_t dn = 0;
408  
    std::size_t n = 0;
408  
    std::size_t n = 0;
409  
    if (sign != '-')
409  
    if (sign != '-')
410  
    {
410  
    {
411  
        dn += measure_one(sign, cs);
411  
        dn += measure_one(sign, cs);
412  
        ++n;
412  
        ++n;
413  
    }
413  
    }
414  
    do
414  
    do
415  
    {
415  
    {
416  
        int d = v % 10;
416  
        int d = v % 10;
417  
        v /= 10;
417  
        v /= 10;
418  
        dn += measure_one('0' + static_cast<char>(d), cs);
418  
        dn += measure_one('0' + static_cast<char>(d), cs);
419  
        ++n;
419  
        ++n;
420  
    }
420  
    }
421  
    while (v != 0);
421  
    while (v != 0);
422  

422  

423  
    std::size_t w = width;
423  
    std::size_t w = width;
424  
    if (width_idx != std::size_t(-1) ||
424  
    if (width_idx != std::size_t(-1) ||
425  
        !width_name.empty())
425  
        !width_name.empty())
426  
    {
426  
    {
427  
        get_width_from_args(
427  
        get_width_from_args(
428  
            width_idx, width_name, ctx.args(), w);
428  
            width_idx, width_name, ctx.args(), w);
429  
    }
429  
    }
430  
    if (w > n)
430  
    if (w > n)
431  
    {
431  
    {
432  
        if (!zeros)
432  
        if (!zeros)
433  
            dn += measure_one(fill, cs) * (w - n);
433  
            dn += measure_one(fill, cs) * (w - n);
434  
        else
434  
        else
435  
            dn += measure_one('0', cs) * (w - n);
435  
            dn += measure_one('0', cs) * (w - n);
436  
    }
436  
    }
437  
    return ctx.out() + dn;
437  
    return ctx.out() + dn;
438  
}
438  
}
439  

439  

440  
char*
440  
char*
441  
integer_formatter_impl::
441  
integer_formatter_impl::
442  
format(
442  
format(
443  
    long long int v,
443  
    long long int v,
444  
    format_context& ctx,
444  
    format_context& ctx,
445  
    grammar::lut_chars const& cs) const
445  
    grammar::lut_chars const& cs) const
446  
{
446  
{
447  
    // get n digits
447  
    // get n digits
448  
    long long int v0 = v;
448  
    long long int v0 = v;
449  
    long long int p = 1;
449  
    long long int p = 1;
450  
    std::size_t n = 0;
450  
    std::size_t n = 0;
451  
    if (v < 0)
451  
    if (v < 0)
452  
    {
452  
    {
453  
        v *= - 1;
453  
        v *= - 1;
454  
        ++n;
454  
        ++n;
455  
    }
455  
    }
456  
    else if (sign != '-')
456  
    else if (sign != '-')
457  
    {
457  
    {
458  
        ++n;
458  
        ++n;
459  
    }
459  
    }
460  
    do
460  
    do
461  
    {
461  
    {
462  
        if (v >= 10)
462  
        if (v >= 10)
463  
            p *= 10;
463  
            p *= 10;
464  
        v /= 10;
464  
        v /= 10;
465  
        ++n;
465  
        ++n;
466  
    }
466  
    }
467  
    while (v > 0);
467  
    while (v > 0);
468  
    static constexpr auto m =
468  
    static constexpr auto m =
469  
        std::numeric_limits<long long int>::digits10;
469  
        std::numeric_limits<long long int>::digits10;
470  
    BOOST_ASSERT(n <= m + 1);
470  
    BOOST_ASSERT(n <= m + 1);
471  
    ignore_unused(m);
471  
    ignore_unused(m);
472  

472  

473  
    // get pad
473  
    // get pad
474  
    std::size_t w = width;
474  
    std::size_t w = width;
475  
    if (width_idx != std::size_t(-1) ||
475  
    if (width_idx != std::size_t(-1) ||
476  
        !width_name.empty())
476  
        !width_name.empty())
477  
    {
477  
    {
478  
        get_width_from_args(
478  
        get_width_from_args(
479  
            width_idx, width_name, ctx.args(), w);
479  
            width_idx, width_name, ctx.args(), w);
480  
    }
480  
    }
481  
    std::size_t lpad = 0;
481  
    std::size_t lpad = 0;
482  
    std::size_t rpad = 0;
482  
    std::size_t rpad = 0;
483  
    if (w > n)
483  
    if (w > n)
484  
    {
484  
    {
485  
        std::size_t pad = w - n;
485  
        std::size_t pad = w - n;
486  
        if (zeros)
486  
        if (zeros)
487  
        {
487  
        {
488  
            lpad = pad;
488  
            lpad = pad;
489  
        }
489  
        }
490  
        else
490  
        else
491  
        {
491  
        {
492  
            switch (align)
492  
            switch (align)
493  
            {
493  
            {
494  
            case '<':
494  
            case '<':
495  
                rpad = pad;
495  
                rpad = pad;
496  
                break;
496  
                break;
497  
            case '>':
497  
            case '>':
498  
                lpad = pad;
498  
                lpad = pad;
499  
                break;
499  
                break;
500  
            case '^':
500  
            case '^':
501  
                lpad = pad / 2;
501  
                lpad = pad / 2;
502  
                rpad = pad - lpad;
502  
                rpad = pad - lpad;
503  
                break;
503  
                break;
504  
            }
504  
            }
505  
        }
505  
        }
506  
    }
506  
    }
507  

507  

508  
    // write
508  
    // write
509  
    v = v0;
509  
    v = v0;
510  
    char* out = ctx.out();
510  
    char* out = ctx.out();
511  
    if (!zeros)
511  
    if (!zeros)
512  
    {
512  
    {
513  
        for (std::size_t i = 0; i < lpad; ++i)
513  
        for (std::size_t i = 0; i < lpad; ++i)
514  
            encode_one(out, fill, cs);
514  
            encode_one(out, fill, cs);
515  
    }
515  
    }
516  
    if (v < 0)
516  
    if (v < 0)
517  
    {
517  
    {
518  
        encode_one(out, '-', cs);
518  
        encode_one(out, '-', cs);
519  
        v *= -1;
519  
        v *= -1;
520  
        --n;
520  
        --n;
521  
    }
521  
    }
522  
    else if (sign != '-')
522  
    else if (sign != '-')
523  
    {
523  
    {
524  
        encode_one(out, sign, cs);
524  
        encode_one(out, sign, cs);
525  
        --n;
525  
        --n;
526  
    }
526  
    }
527  
    if (zeros)
527  
    if (zeros)
528  
    {
528  
    {
529  
        for (std::size_t i = 0; i < lpad; ++i)
529  
        for (std::size_t i = 0; i < lpad; ++i)
530  
            encode_one(out, '0', cs);
530  
            encode_one(out, '0', cs);
531  
    }
531  
    }
532  
    while (n)
532  
    while (n)
533  
    {
533  
    {
534  
        unsigned long long int d = v / p;
534  
        unsigned long long int d = v / p;
535  
        encode_one(out, '0' + static_cast<char>(d), cs);
535  
        encode_one(out, '0' + static_cast<char>(d), cs);
536  
        --n;
536  
        --n;
537  
        v %= p;
537  
        v %= p;
538  
        p /= 10;
538  
        p /= 10;
539  
    }
539  
    }
540  
    if (!zeros)
540  
    if (!zeros)
541  
    {
541  
    {
542  
        for (std::size_t i = 0; i < rpad; ++i)
542  
        for (std::size_t i = 0; i < rpad; ++i)
543  
            encode_one(out, fill, cs);
543  
            encode_one(out, fill, cs);
544  
    }
544  
    }
545  
    return out;
545  
    return out;
546  
}
546  
}
547  

547  

548  
char*
548  
char*
549  
integer_formatter_impl::
549  
integer_formatter_impl::
550  
format(
550  
format(
551  
unsigned long long int v,
551  
unsigned long long int v,
552  
format_context& ctx,
552  
format_context& ctx,
553  
grammar::lut_chars const& cs) const
553  
grammar::lut_chars const& cs) const
554  
{
554  
{
555  
    // get n digits
555  
    // get n digits
556  
    unsigned long long int v0 = v;
556  
    unsigned long long int v0 = v;
557  
    unsigned long long int p = 1;
557  
    unsigned long long int p = 1;
558  
    std::size_t n = 0;
558  
    std::size_t n = 0;
559  
    if (sign != '-')
559  
    if (sign != '-')
560  
    {
560  
    {
561  
        ++n;
561  
        ++n;
562  
    }
562  
    }
563  
    do
563  
    do
564  
    {
564  
    {
565  
        if (v >= 10)
565  
        if (v >= 10)
566  
            p *= 10;
566  
            p *= 10;
567  
        v /= 10;
567  
        v /= 10;
568  
        ++n;
568  
        ++n;
569  
    }
569  
    }
570  
    while (v > 0);
570  
    while (v > 0);
571  
    static constexpr auto m =
571  
    static constexpr auto m =
572  
        std::numeric_limits<unsigned long long int>::digits10;
572  
        std::numeric_limits<unsigned long long int>::digits10;
573  
    BOOST_ASSERT(n <= m + 1);
573  
    BOOST_ASSERT(n <= m + 1);
574  
    ignore_unused(m);
574  
    ignore_unused(m);
575  

575  

576  
    // get pad
576  
    // get pad
577  
    std::size_t w = width;
577  
    std::size_t w = width;
578  
    if (width_idx != std::size_t(-1) ||
578  
    if (width_idx != std::size_t(-1) ||
579  
        !width_name.empty())
579  
        !width_name.empty())
580  
    {
580  
    {
581  
        get_width_from_args(
581  
        get_width_from_args(
582  
            width_idx, width_name, ctx.args(), w);
582  
            width_idx, width_name, ctx.args(), w);
583  
    }
583  
    }
584  
    std::size_t lpad = 0;
584  
    std::size_t lpad = 0;
585  
    std::size_t rpad = 0;
585  
    std::size_t rpad = 0;
586  
    if (w > n)
586  
    if (w > n)
587  
    {
587  
    {
588  
        std::size_t pad = w - n;
588  
        std::size_t pad = w - n;
589  
        if (zeros)
589  
        if (zeros)
590  
        {
590  
        {
591  
            lpad = pad;
591  
            lpad = pad;
592  
        }
592  
        }
593  
        else
593  
        else
594  
        {
594  
        {
595  
            switch (align)
595  
            switch (align)
596  
            {
596  
            {
597  
            case '<':
597  
            case '<':
598  
                rpad = pad;
598  
                rpad = pad;
599  
                break;
599  
                break;
600  
            case '>':
600  
            case '>':
601  
                lpad = pad;
601  
                lpad = pad;
602  
                break;
602  
                break;
603  
            case '^':
603  
            case '^':
604  
                lpad = pad / 2;
604  
                lpad = pad / 2;
605  
                rpad = pad - lpad;
605  
                rpad = pad - lpad;
606  
                break;
606  
                break;
607  
            }
607  
            }
608  
        }
608  
        }
609  
    }
609  
    }
610  

610  

611  
    // write
611  
    // write
612  
    v = v0;
612  
    v = v0;
613  
    char* out = ctx.out();
613  
    char* out = ctx.out();
614  
    if (!zeros)
614  
    if (!zeros)
615  
    {
615  
    {
616  
        for (std::size_t i = 0; i < lpad; ++i)
616  
        for (std::size_t i = 0; i < lpad; ++i)
617  
            encode_one(out, fill, cs);
617  
            encode_one(out, fill, cs);
618  
    }
618  
    }
619  
    if (sign != '-')
619  
    if (sign != '-')
620  
    {
620  
    {
621  
        encode_one(out, sign, cs);
621  
        encode_one(out, sign, cs);
622  
        --n;
622  
        --n;
623  
    }
623  
    }
624  
    if (zeros)
624  
    if (zeros)
625  
    {
625  
    {
626  
        for (std::size_t i = 0; i < lpad; ++i)
626  
        for (std::size_t i = 0; i < lpad; ++i)
627  
            encode_one(out, '0', cs);
627  
            encode_one(out, '0', cs);
628  
    }
628  
    }
629  
    while (n)
629  
    while (n)
630  
    {
630  
    {
631  
        unsigned long long int d = v / p;
631  
        unsigned long long int d = v / p;
632  
        encode_one(out, '0' + static_cast<char>(d), cs);
632  
        encode_one(out, '0' + static_cast<char>(d), cs);
633  
        --n;
633  
        --n;
634  
        v %= p;
634  
        v %= p;
635  
        p /= 10;
635  
        p /= 10;
636  
    }
636  
    }
637  
    if (!zeros)
637  
    if (!zeros)
638  
    {
638  
    {
639  
        for (std::size_t i = 0; i < rpad; ++i)
639  
        for (std::size_t i = 0; i < rpad; ++i)
640  
            encode_one(out, fill, cs);
640  
            encode_one(out, fill, cs);
641  
    }
641  
    }
642  
    return out;
642  
    return out;
643  
}
643  
}
644  

644  

645  
} // detail
645  
} // detail
646  
} // urls
646  
} // urls
647  
} // boost
647  
} // boost
648  

648