GCC Code Coverage Report


Directory: ./
File: libs/beast2/include/boost/beast2/format.hpp
Date: 2025-12-24 17:07:59
Exec Total Coverage
Lines: 84 86 97.7%
Functions: 27 42 64.3%
Branches: 46 48 95.8%

Line Branch Exec Source
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/beast2/detail/except.hpp>
15 #include <boost/core/detail/string_view.hpp>
16
17 #include <memory>
18 #include <ostream>
19 #include <streambuf>
20 #include <string>
21
22 namespace boost {
23 namespace beast2 {
24
25 namespace detail {
26
27 struct format_impl
28 {
29 std::ostream& os;
30 core::string_view fs;
31 char const* p;
32 char const* p0;
33 char const* end;
34 bool has_placeholder = false;
35
36 27 format_impl(
37 std::ostream& os_,
38 core::string_view fs_)
39 27 : os(os_)
40 27 , fs(fs_)
41 27 , p(fs.data())
42 27 , p0(p)
43 27 , end(p + fs.size())
44 {
45 27 }
46
47 core::string_view
48 57 next()
49 {
50 57 has_placeholder = false;
51 57 bool unmatched_open = false;
52 57 bool unmatched_close = false;
53
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 31 times.
116 while (p != end)
54 {
55
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 67 times.
85 if(unmatched_open)
56 {
57
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 13 times.
18 if(*p == '{')
58 {
59 5 p++;
60 5 core::string_view seg(p0, (p - 1) - p0);
61 5 p0 = p;
62 5 return seg;
63 }
64
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 if(*p == '}')
65 {
66 13 p++;
67 13 core::string_view seg(p0, (p - 2) - p0);
68 13 p0 = p;
69 13 has_placeholder = true;
70 13 return seg;
71 }
72 detail::throw_invalid_argument(
73 "invalid format string, unmatched {");
74 }
75
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 59 times.
67 if(unmatched_close)
76 {
77
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 if(*p == '}')
78 {
79 5 p++;
80 5 core::string_view seg(p0, (p - 1) - p0);
81 5 p0 = p;
82 5 return seg;
83 }
84 3 detail::throw_invalid_argument(
85 "invalid format string, unmatched }");
86 }
87
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 38 times.
59 if (*p == '{')
88 {
89 21 unmatched_open = true;
90 }
91
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 48 times.
59 if(*p == '}')
92 {
93 11 unmatched_close = true;
94 }
95 59 p++;
96 }
97
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 28 times.
31 if (unmatched_open)
98 3 detail::throw_invalid_argument(
99 "invalid format string, unmatched {");
100
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 25 times.
28 if(unmatched_close)
101 3 detail::throw_invalid_argument(
102 "invalid format string, unmatched }");
103
104 core::string_view seg(
105 25 p0, end - p0);
106 25 p0 = end;
107 25 return seg;
108 }
109
110 template<class Arg>
111 40 void do_arg(Arg const& arg)
112 {
113
1/1
✓ Branch 1 taken 14 times.
40 core::string_view seg = next();
114
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 7 times.
38 while(seg.size())
115 {
116
1/1
✓ Branch 3 taken 12 times.
24 os.write(seg.data(), static_cast<std::streamsize>(seg.size()));
117
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 5 times.
24 if(has_placeholder)
118 14 break;
119
1/1
✓ Branch 1 taken 5 times.
10 seg = next();
120 }
121
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
28 if(has_placeholder)
122
1/1
✓ Branch 1 taken 10 times.
20 os << arg;
123 28 };
124
125 template<class... Args>
126 54 void operator()(Args const&... args)
127 {
128 using expander = int[];
129
3/3
✓ Branch 1 taken 11 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 1 times.
54 (void)expander{0, (do_arg(args), 0)...};
130
131 42 core::string_view seg;
132 do
133 {
134
1/1
✓ Branch 1 taken 29 times.
64 seg = next();
135
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 26 times.
58 if(has_placeholder)
136 6 detail::throw_invalid_argument(
137 "too few format arguments provided");
138
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 15 times.
52 if(seg.size())
139
1/1
✓ Branch 3 taken 11 times.
22 os.write(seg.data(), static_cast<std::streamsize>(seg.size()));
140 }
141
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 15 times.
52 while(seg.size());
142 30 }
143 };
144
145 class appendbuf : public std::streambuf
146 {
147 std::string* s_;
148
149 protected:
150 // Called when a single character is to be written
151 1 virtual int_type overflow(int_type ch) override
152 {
153
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (ch != traits_type::eof())
154 {
155 1 s_->push_back(static_cast<char>(ch));
156 1 return ch;
157 }
158 return traits_type::eof();
159 }
160
161 // Called when multiple characters are to be written
162 32 virtual std::streamsize xsputn(const char* s, std::streamsize n) override
163 {
164 32 s_->append(s, static_cast<std::size_t>(n));
165 32 return n;
166 }
167
168 public:
169 27 explicit appendbuf(std::string& s)
170 27 : s_(&s)
171 {
172 27 }
173 };
174
175 class appendstream : public std::ostream
176 {
177 appendbuf buf_;
178
179 public:
180 27 explicit appendstream(std::string& s)
181 27 : std::ostream(&buf_)
182
2/2
✓ Branch 2 taken 27 times.
✓ Branch 5 taken 27 times.
27 , buf_(s)
183 {
184 27 }
185 };
186
187 } // detail
188
189 /** Format arguments using a format string
190 */
191 template<class... Args>
192 void
193 54 format_to(
194 std::ostream& os,
195 core::string_view fs,
196 Args const&... args)
197 {
198
1/1
✓ Branch 2 taken 15 times.
54 detail::format_impl(os, fs)(args...);
199 30 }
200
201 /** Format arguments using a format string
202 */
203 template<class... Args>
204 void
205 54 format_to(
206 std::string& dest,
207 core::string_view fs,
208 Args const&... args)
209 {
210
1/1
✓ Branch 1 taken 27 times.
54 detail::appendstream ss(dest);
211
1/1
✓ Branch 1 taken 15 times.
54 format_to(ss, fs, args...);
212 54 }
213
214 } // beast2
215 } // boost
216
217 #endif
218