GCC Code Coverage Report


Directory: libs/url/
File: boost/url/impl/encode.hpp
Date: 2024-03-13 19:32:03
Exec Total Coverage
Lines: 98 99 99.0%
Functions: 10 10 100.0%
Branches: 59 70 84.3%

Line Branch Exec Source
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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/boostorg/url
8 //
9
10 #ifndef BOOST_URL_IMPL_ENCODE_HPP
11 #define BOOST_URL_IMPL_ENCODE_HPP
12
13 #include <boost/url/detail/encode.hpp>
14 #include <boost/url/detail/except.hpp>
15 #include <boost/url/encoding_opts.hpp>
16 #include <boost/url/grammar/charset.hpp>
17 #include <boost/url/grammar/hexdig_chars.hpp>
18 #include <boost/url/grammar/type_traits.hpp>
19 #include <boost/assert.hpp>
20 #include <boost/static_assert.hpp>
21
22 namespace boost {
23 namespace urls {
24
25 //------------------------------------------------
26
27 template<class CharSet>
28 std::size_t
29 899 encoded_size(
30 core::string_view s,
31 CharSet const& unreserved,
32 encoding_opts opt) noexcept
33 {
34 /* If you get a compile error here, it
35 means that the value you passed does
36 not meet the requirements stated in
37 the documentation.
38 */
39 static_assert(
40 grammar::is_charset<CharSet>::value,
41 "Type requirements not met");
42
43 899 std::size_t n = 0;
44 899 auto it = s.data();
45 899 auto const last = it + s.size();
46
47
5/6
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 833 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
✓ Branch 4 taken 833 times.
✓ Branch 5 taken 22 times.
942 if(! opt.space_as_plus ||
48 43 unreserved(' '))
49 {
50
2/2
✓ Branch 0 taken 3915 times.
✓ Branch 1 taken 833 times.
4809 while(it != last)
51 {
52
2/2
✓ Branch 1 taken 3764 times.
✓ Branch 2 taken 151 times.
3953 if(unreserved(*it))
53 3783 n += 1;
54 else
55 170 n += 3;
56 3953 ++it;
57 }
58 }
59 else
60 {
61
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 22 times.
116 while(it != last)
62 {
63 73 auto c = *it;
64
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 18 times.
73 if(unreserved(c))
65 38 ++n;
66
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
35 else if(c == ' ')
67 17 ++n;
68 else
69 18 n += 3;
70 73 ++it;
71 }
72 }
73 899 return n;
74 }
75
76 //------------------------------------------------
77
78 template<class CharSet>
79 std::size_t
80 600 encode(
81 char* dest,
82 std::size_t size,
83 core::string_view s,
84 CharSet const& unreserved,
85 encoding_opts opt)
86 {
87 /* If you get a compile error here, it
88 means that the value you passed does
89 not meet the requirements stated in
90 the documentation.
91 */
92 static_assert(
93 grammar::is_charset<CharSet>::value,
94 "Type requirements not met");
95
96 // '%' must be reserved
97
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 487 times.
488 BOOST_ASSERT(! unreserved('%'));
98
99 600 char const* const hex =
100 600 detail::hexdigs[opt.lower_case];
101 710 auto const encode = [hex](
102 char*& dest,
103 unsigned char c) noexcept
104 {
105 110 *dest++ = '%';
106 110 *dest++ = hex[c>>4];
107 110 *dest++ = hex[c&0xf];
108 };
109
110 600 auto it = s.data();
111 600 auto const end = dest + size;
112 600 auto const last = it + s.size();
113 600 auto const dest0 = dest;
114 600 auto const end3 = end - 3;
115
116
2/2
✓ Branch 0 taken 517 times.
✓ Branch 1 taken 26 times.
600 if(! opt.space_as_plus)
117 {
118
2/2
✓ Branch 0 taken 2787 times.
✓ Branch 1 taken 499 times.
3358 while(it != last)
119 {
120
2/2
✓ Branch 1 taken 2668 times.
✓ Branch 2 taken 119 times.
2846 if(unreserved(*it))
121 {
122
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2665 times.
2698 if(dest == end)
123 6 return dest - dest0;
124 2692 *dest++ = *it++;
125 2692 continue;
126 }
127
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 104 times.
148 if(dest > end3)
128 30 return dest - dest0;
129 118 encode(dest, *it++);
130 }
131 512 return dest - dest0;
132 }
133
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
52 else if(! unreserved(' '))
134 {
135 // VFALCO space is usually reserved,
136 // and we depend on this for an
137 // optimization. if this assert
138 // goes off we can split the loop
139 // below into two versions.
140 BOOST_ASSERT(! unreserved(' '));
141
142
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 12 times.
104 while(it != last)
143 {
144
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 24 times.
80 if(unreserved(*it))
145 {
146
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 13 times.
32 if(dest == end)
147 6 return dest - dest0;
148 26 *dest++ = *it++;
149 26 continue;
150 }
151
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 15 times.
48 if(*it == ' ')
152 {
153
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
18 if(dest == end)
154 4 return dest - dest0;
155 14 *dest++ = '+';
156 14 ++it;
157 14 continue;
158 }
159
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6 times.
30 if(dest > end3)
160 18 return dest - dest0;
161 12 encode(dest, *it++);
162 }
163 }
164 24 return dest - dest0;
165 }
166
167 //------------------------------------------------
168
169 // unsafe encode just
170 // asserts on the output buffer
171 //
172 template<class CharSet>
173 std::size_t
174 175 encode_unsafe(
175 char* dest,
176 std::size_t size,
177 core::string_view s,
178 CharSet const& unreserved,
179 encoding_opts opt)
180 {
181 // '%' must be reserved
182
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 158 times.
158 BOOST_ASSERT(! unreserved('%'));
183
184 175 auto it = s.data();
185 175 auto const last = it + s.size();
186 175 auto const end = dest + size;
187 ignore_unused(end);
188
189 175 char const* const hex =
190 175 detail::hexdigs[opt.lower_case];
191 359 auto const encode = [end, hex](
192 char*& dest,
193 unsigned char c) noexcept
194 {
195 46 ignore_unused(end);
196 46 *dest++ = '%';
197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 BOOST_ASSERT(dest != end);
198 46 *dest++ = hex[c>>4];
199
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 BOOST_ASSERT(dest != end);
200 46 *dest++ = hex[c&0xf];
201 };
202
203 175 auto const dest0 = dest;
204
2/2
✓ Branch 0 taken 166 times.
✓ Branch 1 taken 9 times.
175 if(! opt.space_as_plus)
205 {
206
2/2
✓ Branch 0 taken 439 times.
✓ Branch 1 taken 166 times.
605 while(it != last)
207 {
208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 439 times.
439 BOOST_ASSERT(dest != end);
209
2/2
✓ Branch 1 taken 396 times.
✓ Branch 2 taken 43 times.
439 if(unreserved(*it))
210 396 *dest++ = *it++;
211 else
212 43 encode(dest, *it++);
213 }
214 }
215 else
216 {
217 // VFALCO space is usually reserved,
218 // and we depend on this for an
219 // optimization. if this assert
220 // goes off we can split the loop
221 // below into two versions.
222
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 BOOST_ASSERT(! unreserved(' '));
223
224
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 9 times.
37 while(it != last)
225 {
226
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 BOOST_ASSERT(dest != end);
227
2/2
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 8 times.
28 if(unreserved(*it))
228 {
229 20 *dest++ = *it++;
230 }
231
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 else if(*it == ' ')
232 {
233 5 *dest++ = '+';
234 5 ++it;
235 }
236 else
237 {
238 3 encode(dest, *it++);
239 }
240 }
241 }
242 175 return dest - dest0;
243 }
244
245 //------------------------------------------------
246
247 template<
248 class StringToken,
249 class CharSet>
250 BOOST_URL_STRTOK_RETURN
251 24 encode(
252 core::string_view s,
253 CharSet const& unreserved,
254 encoding_opts opt,
255 StringToken&& token) noexcept
256 {
257 /* If you get a compile error here, it
258 means that the value you passed does
259 not meet the requirements stated in
260 the documentation.
261 */
262 static_assert(
263 grammar::is_charset<CharSet>::value,
264 "Type requirements not met");
265
266 24 auto const n = encoded_size(
267 s, unreserved, opt);
268 24 auto p = token.prepare(n);
269
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 2 times.
24 if(n > 0)
270 22 encode_unsafe(
271 p, n, s, unreserved, opt);
272 24 return token.result();
273 }
274
275 } // urls
276 } // boost
277
278 #endif
279