GCC Code Coverage Report


Directory: libs/url/
File: libs/url/src/ipv6_address.cpp
Date: 2024-02-29 20:02:56
Exec Total Coverage
Lines: 125 125 100.0%
Functions: 13 13 100.0%
Branches: 56 62 90.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_IPV6_ADDRESS_IPP
11 #define BOOST_URL_IMPL_IPV6_ADDRESS_IPP
12
13 #include <boost/url/detail/config.hpp>
14 #include <boost/url/ipv6_address.hpp>
15 #include <boost/url/ipv4_address.hpp>
16 #include <boost/url/rfc/ipv6_address_rule.hpp>
17 #include <boost/url/detail/except.hpp>
18 #include <boost/url/grammar/parse.hpp>
19 #include <cstring>
20
21 namespace boost {
22 namespace urls {
23
24 210 ipv6_address::
25 ipv6_address(
26 210 bytes_type const& bytes) noexcept
27 {
28 210 std::memcpy(&addr_,
29 210 bytes.data(), 16);
30 210 }
31
32 4 ipv6_address::
33 ipv6_address(
34 4 ipv4_address const& addr) noexcept
35 {
36 4 auto const v = addr.to_bytes();
37 4 ipv6_address::bytes_type bytes = {
38 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39 4 0xff, 0xff, v[0], v[1], v[2], v[3] } };
40 4 std::memcpy(&addr_, bytes.data(), 16);
41 4 }
42
43 58 ipv6_address::
44 ipv6_address(
45 58 core::string_view s)
46 : ipv6_address(
47 58 parse_ipv6_address(s
48
2/2
✓ Branch 3 taken 57 times.
✓ Branch 4 taken 1 times.
58 ).value(BOOST_URL_POS))
49 {
50 57 }
51
52 core::string_view
53 14 ipv6_address::
54 to_buffer(
55 char* dest,
56 std::size_t dest_size) const
57 {
58
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 13 times.
14 if(dest_size < max_str_len)
59 1 detail::throw_length_error();
60 13 auto n = print_impl(dest);
61 13 return core::string_view(dest, n);
62 }
63
64 bool
65 3 ipv6_address::
66 is_loopback() const noexcept
67 {
68 3 return *this == loopback();
69 }
70
71 bool
72 3 ipv6_address::
73 is_unspecified() const noexcept
74 {
75 3 return *this == ipv6_address();
76 }
77
78 bool
79 56 ipv6_address::
80 is_v4_mapped() const noexcept
81 {
82 return
83
2/2
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 16 times.
103 addr_[ 0] == 0 && addr_[ 1] == 0 &&
84
3/4
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 2 times.
31 addr_[ 2] == 0 && addr_[ 3] == 0 &&
85
3/4
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 2 times.
29 addr_[ 4] == 0 && addr_[ 5] == 0 &&
86
3/4
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25 times.
✓ Branch 5 taken 2 times.
27 addr_[ 6] == 0 && addr_[ 7] == 0 &&
87
3/4
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 2 times.
25 addr_[ 8] == 0 && addr_[ 9] == 0 &&
88
4/4
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 9 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 11 times.
115 addr_[10] == 0xff &&
89
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
68 addr_[11] == 0xff;
90 }
91
92 ipv6_address
93 5 ipv6_address::
94 loopback() noexcept
95 {
96 5 ipv6_address a;
97 5 a.addr_[15] = 1;
98 5 return a;
99 }
100
101 std::size_t
102 51 ipv6_address::
103 print_impl(
104 char* dest) const noexcept
105 {
106 auto const count_zeroes =
107 169 []( unsigned char const* first,
108 unsigned char const* const last)
109 {
110 169 std::size_t n = 0;
111
2/2
✓ Branch 0 taken 425 times.
✓ Branch 1 taken 23 times.
448 while(first != last)
112 {
113
2/2
✓ Branch 0 taken 364 times.
✓ Branch 1 taken 61 times.
425 if( first[0] != 0 ||
114
2/2
✓ Branch 0 taken 279 times.
✓ Branch 1 taken 85 times.
364 first[1] != 0)
115 break;
116 279 n += 2;
117 279 first += 2;
118 }
119 169 return n;
120 };
121 auto const print_hex =
122 135 []( char* dest,
123 unsigned short v)
124 {
125 135 char const* const dig =
126 "0123456789abcdef";
127
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 87 times.
135 if(v >= 0x1000)
128 {
129 48 *dest++ = dig[v>>12];
130 48 v &= 0x0fff;
131 48 *dest++ = dig[v>>8];
132 48 v &= 0x0ff;
133 48 *dest++ = dig[v>>4];
134 48 v &= 0x0f;
135 48 *dest++ = dig[v];
136 }
137
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 85 times.
87 else if(v >= 0x100)
138 {
139 2 *dest++ = dig[v>>8];
140 2 v &= 0x0ff;
141 2 *dest++ = dig[v>>4];
142 2 v &= 0x0f;
143 2 *dest++ = dig[v];
144 }
145
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 84 times.
85 else if(v >= 0x10)
146 {
147 1 *dest++ = dig[v>>4];
148 1 v &= 0x0f;
149 1 *dest++ = dig[v];
150 }
151 else
152 {
153 84 *dest++ = dig[v];
154 }
155 135 return dest;
156 };
157 51 auto const dest0 = dest;
158 // find longest run of zeroes
159 51 std::size_t best_len = 0;
160 51 int best_pos = -1;
161 51 auto it = addr_.data();
162 auto const v4 =
163 51 is_v4_mapped();
164
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 42 times.
93 auto const end = v4 ?
165 9 (it + addr_.size() - 4)
166 93 : it + addr_.size();
167
2/2
✓ Branch 0 taken 169 times.
✓ Branch 1 taken 51 times.
220 while(it != end)
168 {
169 169 auto n = count_zeroes(
170 it, end);
171
2/2
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 58 times.
169 if(n == 0)
172 {
173 111 it += 2;
174 111 continue;
175 }
176
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 6 times.
58 if(n > best_len)
177 {
178 52 best_pos = static_cast<
179 52 int>(it - addr_.data());
180 52 best_len = n;
181 }
182 58 it += n;
183 }
184 51 it = addr_.data();
185
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 21 times.
51 if(best_pos != 0)
186 {
187 30 unsigned short v =
188 30 (it[0] * 256U) + it[1];
189 30 dest = print_hex(dest, v);
190 30 it += 2;
191 }
192 else
193 {
194 21 *dest++ = ':';
195 21 it += best_len;
196
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 19 times.
21 if(it == end)
197 2 *dest++ = ':';
198 }
199
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 51 times.
181 while(it != end)
200 {
201 130 *dest++ = ':';
202 130 if(it - addr_.data() ==
203
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 105 times.
130 best_pos)
204 {
205 25 it += best_len;
206
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 10 times.
25 if(it == end)
207 15 *dest++ = ':';
208 25 continue;
209 }
210 105 unsigned short v =
211 105 (it[0] * 256U) + it[1];
212 105 dest = print_hex(dest, v);
213 105 it += 2;
214 }
215
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 42 times.
51 if(v4)
216 {
217 ipv4_address::bytes_type bytes;
218 9 bytes[0] = it[0];
219 9 bytes[1] = it[1];
220 9 bytes[2] = it[2];
221 9 bytes[3] = it[3];
222 9 ipv4_address a(bytes);
223 9 *dest++ = ':';
224 9 dest += a.print_impl(dest);
225 }
226 51 return dest - dest0;
227 }
228
229 void
230 38 ipv6_address::
231 to_string_impl(
232 string_token::arg& t) const
233 {
234 char buf[max_str_len];
235 38 auto const n = print_impl(buf);
236
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
38 char* dest = t.prepare(n);
237 38 std::memcpy(dest, buf, n);
238 38 }
239
240 //------------------------------------------------
241
242 auto
243 204 parse_ipv6_address(
244 core::string_view s) noexcept ->
245 system::result<ipv6_address>
246 {
247 return grammar::parse(
248 204 s, ipv6_address_rule);
249 }
250
251 } // urls
252 } // boost
253
254 #endif
255