Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
3 : //
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)
6 : //
7 : // Official repository: https://github.com/cppalliance/beast2
8 : //
9 :
10 : #ifndef BOOST_BEAST2_FORMAT_HPP
11 : #define BOOST_BEAST2_FORMAT_HPP
12 :
13 : #include <boost/beast2/detail/config.hpp>
14 : #include <boost/core/detail/string_view.hpp>
15 : #include <memory>
16 : #include <ostream>
17 : #include <streambuf>
18 : #include <string>
19 :
20 : namespace boost {
21 : namespace beast2 {
22 :
23 : namespace detail {
24 :
25 : struct format_impl
26 : {
27 : std::ostream& os;
28 : core::string_view fs;
29 : char const* p;
30 : char const* p0;
31 : char const* end;
32 : bool has_placeholder = false;
33 :
34 14 : format_impl(
35 : std::ostream& os_,
36 : core::string_view fs_)
37 14 : : os(os_)
38 14 : , fs(fs_)
39 14 : , p(fs.data())
40 14 : , p0(p)
41 14 : , end(p + fs.size())
42 : {
43 14 : }
44 :
45 : core::string_view
46 8 : next()
47 : {
48 8 : has_placeholder = false;
49 19 : while (p != end)
50 : {
51 18 : if (*p++ != '{')
52 11 : continue;
53 7 : if (p == end)
54 2 : break;
55 5 : if (*p++ == '}')
56 : {
57 : core::string_view seg(
58 5 : p0, (p - 2) - p0);
59 5 : p0 = p;
60 5 : has_placeholder = true;
61 5 : return seg;
62 : }
63 : }
64 : core::string_view seg(
65 3 : p0, end - p0);
66 3 : p0 = end;
67 3 : return seg;
68 : }
69 :
70 : template<class Arg>
71 8 : void do_arg(Arg const& arg)
72 : {
73 8 : core::string_view seg = next();
74 8 : if (seg.size())
75 7 : os.write(seg.data(), static_cast<
76 7 : std::streamsize>(seg.size()));
77 8 : if (has_placeholder)
78 5 : os << arg;
79 8 : };
80 :
81 : template<class... Args>
82 14 : void operator()(Args const&... args)
83 : {
84 : using expander = int[];
85 14 : (void)expander{0, (do_arg(args), 0)...};
86 14 : if (p0 < end)
87 10 : os.write(p0, static_cast<
88 10 : std::streamsize>(end - p0));
89 14 : }
90 : };
91 :
92 : class appendbuf : public std::streambuf
93 : {
94 : std::string* s_;
95 :
96 : protected:
97 : // Called when a single character is to be written
98 0 : virtual int_type overflow(int_type ch) override
99 : {
100 0 : if (ch != traits_type::eof())
101 : {
102 0 : s_->push_back(static_cast<char>(ch));
103 0 : return ch;
104 : }
105 0 : return traits_type::eof();
106 : }
107 :
108 : // Called when multiple characters are to be written
109 22 : virtual std::streamsize xsputn(const char* s, std::streamsize n) override
110 : {
111 22 : s_->append(s, static_cast<std::size_t>(n));
112 22 : return n;
113 : }
114 :
115 : public:
116 14 : explicit appendbuf(std::string& s)
117 14 : : s_(&s)
118 : {
119 14 : }
120 : };
121 :
122 : class appendstream : public std::ostream
123 : {
124 : appendbuf buf_;
125 :
126 : public:
127 14 : explicit appendstream(std::string& s)
128 14 : : std::ostream(&buf_)
129 14 : , buf_(s)
130 : {
131 14 : }
132 : };
133 :
134 : } // detail
135 :
136 : /** Format arguments using a format string
137 : */
138 : template<class... Args>
139 : void
140 14 : format_to(
141 : std::ostream& os,
142 : core::string_view fs,
143 : Args const&... args)
144 : {
145 14 : detail::format_impl(os, fs)(args...);
146 14 : }
147 :
148 : /** Format arguments using a format string
149 : */
150 : template<class... Args>
151 : void
152 14 : format_to(
153 : std::string& dest,
154 : core::string_view fs,
155 : Args const&... args)
156 : {
157 14 : detail::appendstream ss(dest);
158 14 : format_to(ss, fs, args...);
159 14 : }
160 :
161 : } // beast2
162 : } // boost
163 :
164 : #endif
|