Skip to content

Commit 23636e9

Browse files
authored
Next (#1231)
* Refactor IPv6 address parsing to fix shorten notation handling and improve robustness - Rewrote `scn_cnt_define_in6addr_4_digits_impl` to use loop-based parsing instead of manual unrolling, fixing zero-started validation issues - Completely reimplemented `scn_cnt_define_in6addr_shorten_impl` to properly handle "::" expansion with token-based parsing - Fixed bracket handling in `scn_cnt_define_in6addr_impl` to validate closing bracket and inner content length - Removed unused `scn_cnt_define_in6addr_nonshorten_ * Simplify IPv6 context scanner by removing port parsing and fix EOF handling - Removed port parsing logic from `scan_context_define` for IPv6 addresses to match single-stage parsing behavior - Added special handling in `scn_ctx_define_in6addr_impl` to treat parse failures at buffer end as `parse_code::partial` for streaming contexts - Set `state.size = 1` to mark unfinished IPv6 parse for proper EOF handling, aligning with IPv4 scanner behavior - Eliminated conditional port parsing code path and simplified return * Mark scn_ip_port example as interactive in test configuration - Added `interactive = true` flag for `0042.scn_ip_port` test case to indicate it requires user input * Update addrscn.h * Update addrscn.h * Add IPv4-mapped IPv6 address support with configurable flag for printing and scanning - Added `ipv4_mapped_ipv6` flag to `ip_flags` and `ip_scan_flags` structures (default: true) - Implemented `ipv6_to_ipv4_mapped_bytes` helper to detect and extract IPv4-mapped IPv6 addresses (::ffff:x.x.x.x format) - Modified print functions to output IPv4-mapped IPv6 addresses in compact notation when flag is enabled - Updated scan functions to validate IPv4-mapped IPv6 prefix (first 5 words zero, 6th word 0xFF * Add `ip_scan_no_ipv4_mapped_ipv6` constant flag to disable IPv4-mapped IPv6 address parsing - Added `ip_scan_no_ipv4_mapped_ipv6` inline constexpr flag with `requireport = true` and `ipv4_mapped_ipv6 = false` - Provides predefined configuration to disable IPv4-mapped IPv6 address support while requiring port numbers * Update addrscn.h
1 parent 0e13ffc commit 23636e9

File tree

3 files changed

+245
-62
lines changed

3 files changed

+245
-62
lines changed

include/fast_io_core_impl/integers/impl.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ struct ip_flags
7272
bool v6shorten{true};
7373
bool v6uppercase{};
7474
bool v6bracket{true};
75-
bool v6full{false};
75+
bool v6full{};
7676
bool showport{};
77+
bool ipv4_mapped_ipv6{true};
7778
};
7879

7980
inline constexpr ip_flags ip_default_flags{.showport = true};
@@ -104,9 +105,11 @@ struct ip_scan_flags
104105
bool allowv6bracket{true};
105106
bool requirev6full{false};
106107
bool requireport{false};
108+
bool ipv4_mapped_ipv6{true};
107109
};
108110

109111
inline constexpr ip_scan_flags ip_scan_default_flags{.requireport = true};
112+
inline constexpr ip_scan_flags ip_scan_no_ipv4_mapped_ipv6{.requireport = true, .ipv4_mapped_ipv6 = false};
110113
inline constexpr ip_scan_flags ip_scan_default_inaddr_flags{};
111114

112115
template <ip_scan_flags flags, typename T>

include/fast_io_core_impl/socket/addrprt.h

Lines changed: 145 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,40 @@ inline constexpr char_type *prtrsv_inaddr_common_define_impl(char_type *it,
2222
return it;
2323
}
2424

25+
inline constexpr bool ipv6_to_ipv4_mapped_bytes(::std::uint_least16_t const (&addr)[8],
26+
char unsigned (&out)[4]) noexcept
27+
{
28+
for (::std::size_t i{}; i != 5; ++i)
29+
{
30+
if (addr[i] != 0)
31+
{
32+
return false;
33+
}
34+
}
35+
36+
::std::uint_least16_t w5;
37+
if constexpr (::std::numeric_limits<::std::uint_least16_t>::digits != 16)
38+
{
39+
w5 = ::fast_io::big_endian(addr[5]);
40+
}
41+
else
42+
{
43+
w5 = addr[5];
44+
}
45+
46+
if (w5 != static_cast<::std::uint_least16_t>(0xFFFFu))
47+
{
48+
return false;
49+
}
50+
auto const w6{::fast_io::big_endian(addr[6])};
51+
auto const w7{::fast_io::big_endian(addr[7])};
52+
out[0] = static_cast<char unsigned>(w6 >> 8u);
53+
out[1] = static_cast<char unsigned>(w6 & 0xFFu);
54+
out[2] = static_cast<char unsigned>(w7 >> 8u);
55+
out[3] = static_cast<char unsigned>(w7 & 0xFFu);
56+
return true;
57+
}
58+
2559
template <bool shorten, bool uppercase, bool showv6bracket, bool full, ::std::integral char_type>
2660
inline constexpr char_type *prtrsv_in6addr_common_define_impl(char_type *it,
2761
::std::uint_least16_t const *__restrict start) noexcept
@@ -171,9 +205,54 @@ inline constexpr char_type *prtrsv_ipv4_define_impl(char_type *it, ::fast_io::ip
171205
return it;
172206
}
173207

174-
template <bool v6shorten, bool uppercase, bool showv6bracket, bool showport, bool full, ::std::integral char_type>
208+
template <bool v6shorten, bool uppercase, bool showv6bracket, bool showport, bool full, bool ipv4_mapped_ipv6,
209+
::std::integral char_type>
175210
inline constexpr char_type *prtrsv_inaddr6_define_impl(char_type *it, ::fast_io::posix_in6_addr v) noexcept
176211
{
212+
if constexpr (ipv4_mapped_ipv6)
213+
{
214+
char unsigned v4bytes[4]{};
215+
if (ipv6_to_ipv4_mapped_bytes(v.address, v4bytes))
216+
{
217+
constexpr bool need_bracket{showport ? true : showv6bracket};
218+
if constexpr (need_bracket)
219+
{
220+
*it = ::fast_io::char_literal_v<u8'[', char_type>;
221+
++it;
222+
}
223+
if constexpr (::std::same_as<char_type, char>)
224+
{
225+
it = copy_string_literal("::ffff:", it);
226+
}
227+
else if constexpr (::std::same_as<char_type, wchar_t>)
228+
{
229+
it = copy_string_literal(L"::ffff:", it);
230+
}
231+
else if constexpr (::std::same_as<char_type, char16_t>)
232+
{
233+
it = copy_string_literal(u"::ffff:", it);
234+
}
235+
else if constexpr (::std::same_as<char_type, char32_t>)
236+
{
237+
it = copy_string_literal(U"::ffff:", it);
238+
}
239+
else
240+
{
241+
it = copy_string_literal(u8"::ffff:", it);
242+
}
243+
it = prtrsv_inaddr_common_define_impl(it, v4bytes);
244+
if constexpr (need_bracket)
245+
{
246+
*it = ::fast_io::char_literal_v<u8']', char_type>;
247+
++it;
248+
}
249+
if constexpr (showport)
250+
{
251+
it = prtrsv_ipport_zero_define_impl(it);
252+
}
253+
return it;
254+
}
255+
}
177256
it = prtrsv_in6addr_common_define_impl<v6shorten, uppercase, showport ? true : showv6bracket, full>(it, v.address);
178257
if constexpr (showport)
179258
{
@@ -182,23 +261,70 @@ inline constexpr char_type *prtrsv_inaddr6_define_impl(char_type *it, ::fast_io:
182261
return it;
183262
}
184263

185-
template <bool v6shorten, bool uppercase, bool showv6bracket, bool showport, bool full, ::std::integral char_type>
264+
template <bool v6shorten, bool uppercase, bool showv6bracket, bool showport, bool full, bool ipv4_mapped_ipv6,
265+
::std::integral char_type>
186266
inline constexpr char_type *prtrsv_ipv6_define_impl(char_type *it, ::fast_io::ipv6 v) noexcept
187267
{
188-
it = prtrsv_in6addr_common_define_impl<v6shorten, uppercase, showport ? true : showv6bracket, full>(it, v.address.address);
268+
if constexpr (ipv4_mapped_ipv6)
269+
{
270+
char unsigned v4bytes[4]{};
271+
if (ipv6_to_ipv4_mapped_bytes(v.address.address, v4bytes))
272+
{
273+
constexpr bool need_bracket{showport ? true : showv6bracket};
274+
if constexpr (need_bracket)
275+
{
276+
*it = ::fast_io::char_literal_v<u8'[', char_type>;
277+
++it;
278+
}
279+
if constexpr (::std::same_as<char_type, char>)
280+
{
281+
it = copy_string_literal("::ffff:", it);
282+
}
283+
else if constexpr (::std::same_as<char_type, wchar_t>)
284+
{
285+
it = copy_string_literal(L"::ffff:", it);
286+
}
287+
else if constexpr (::std::same_as<char_type, char16_t>)
288+
{
289+
it = copy_string_literal(u"::ffff:", it);
290+
}
291+
else if constexpr (::std::same_as<char_type, char32_t>)
292+
{
293+
it = copy_string_literal(U"::ffff:", it);
294+
}
295+
else
296+
{
297+
it = copy_string_literal(u8"::ffff:", it);
298+
}
299+
it = prtrsv_inaddr_common_define_impl(it, v4bytes);
300+
if constexpr (need_bracket)
301+
{
302+
*it = ::fast_io::char_literal_v<u8']', char_type>;
303+
++it;
304+
}
305+
if constexpr (showport)
306+
{
307+
it = prtrsv_ipport_define_impl(it, v.port);
308+
}
309+
return it;
310+
}
311+
}
312+
it = prtrsv_in6addr_common_define_impl<v6shorten, uppercase, showport ? true : showv6bracket, full>(it,
313+
v.address.address);
189314
if constexpr (showport)
190315
{
191316
it = prtrsv_ipport_define_impl(it, v.port);
192317
}
193318
return it;
194319
}
195320

196-
template <bool v6shorten, bool uppercase, bool showv6bracket, bool showport, bool full, ::std::integral char_type>
321+
template <bool v6shorten, bool uppercase, bool showv6bracket, bool showport, bool full, bool ipv4_mapped_ipv6,
322+
::std::integral char_type>
197323
inline constexpr char_type *prtrsv_ip_address_define_impl(char_type *it, ::fast_io::ip_address v) noexcept
198324
{
199325
if constexpr (showport)
200326
{
201-
it = prtrsv_ip_address_define_impl<v6shorten, uppercase, showv6bracket, false, full>(it, v);
327+
it = prtrsv_ip_address_define_impl<v6shorten, uppercase, showv6bracket, false, full, ipv4_mapped_ipv6>(it, v);
202328
return prtrsv_ipport_zero_define_impl(it);
203329
}
204330
else
@@ -209,18 +335,19 @@ inline constexpr char_type *prtrsv_ip_address_define_impl(char_type *it, ::fast_
209335
}
210336
else
211337
{
212-
it = prtrsv_in6addr_common_define_impl<v6shorten, uppercase, showport ? true : showv6bracket,
213-
full>(it, v.address.v6.address);
338+
it = prtrsv_inaddr6_define_impl<v6shorten, uppercase, showv6bracket, false, full,
339+
ipv4_mapped_ipv6>(it, v.address.v6);
214340
}
215341
return it;
216342
}
217343
}
218344

219-
template <bool v6shorten, bool uppercase, bool showv6bracket, bool showport, bool full, ::std::integral char_type>
345+
template <bool v6shorten, bool uppercase, bool showv6bracket, bool showport, bool full, bool ipv4_mapped_ipv6,
346+
::std::integral char_type>
220347
inline constexpr char_type *prtrsv_ip_define_impl(char_type *it, ::fast_io::ip v) noexcept
221348
{
222-
it = prtrsv_ip_address_define_impl<v6shorten, uppercase, (showport ? true : showv6bracket), false, full>(it,
223-
v.address);
349+
it = prtrsv_ip_address_define_impl<v6shorten, uppercase, (showport ? true : showv6bracket), false, full,
350+
ipv4_mapped_ipv6>(it, v.address);
224351
if constexpr (showport)
225352
{
226353
it = prtrsv_ipport_define_impl(it, v.port);
@@ -343,22 +470,26 @@ print_reserve_define(::fast_io::io_reserve_type_t<char_type, ::fast_io::manipula
343470
else if constexpr (::std::same_as<iptype, ::fast_io::posix_in6_addr>)
344471
{
345472
return ::fast_io::details::prtrsv_inaddr6_define_impl<flags.v6shorten, flags.v6uppercase,
346-
flags.showport ? true : flags.v6bracket, flags.showport, flags.v6full>(iter, val.reference);
473+
flags.showport ? true : flags.v6bracket, flags.showport, flags.v6full,
474+
flags.ipv4_mapped_ipv6>(iter, val.reference);
347475
}
348476
else if constexpr (::std::same_as<iptype, ::fast_io::ipv6>)
349477
{
350478
return ::fast_io::details::prtrsv_ipv6_define_impl<flags.v6shorten, flags.v6uppercase,
351-
flags.showport ? true : flags.v6bracket, flags.showport, flags.v6full>(iter, val.reference);
479+
flags.showport ? true : flags.v6bracket, flags.showport, flags.v6full,
480+
flags.ipv4_mapped_ipv6>(iter, val.reference);
352481
}
353482
else if constexpr (::std::same_as<iptype, ::fast_io::ip_address>)
354483
{
355484
return ::fast_io::details::prtrsv_ip_address_define_impl<flags.v6shorten, flags.v6uppercase,
356-
flags.showport ? true : flags.v6bracket, flags.showport, flags.v6full>(iter, val.reference);
485+
flags.showport ? true : flags.v6bracket, flags.showport, flags.v6full,
486+
flags.ipv4_mapped_ipv6>(iter, val.reference);
357487
}
358488
else
359489
{
360490
return ::fast_io::details::prtrsv_ip_define_impl<flags.v6shorten, flags.v6uppercase,
361-
flags.showport ? true : flags.v6bracket, flags.showport, flags.v6full>(iter, val.reference);
491+
flags.showport ? true : flags.v6bracket, flags.showport, flags.v6full,
492+
flags.ipv4_mapped_ipv6>(iter, val.reference);
362493
}
363494
}
364495

0 commit comments

Comments
 (0)