@@ -556,20 +556,57 @@ static std::string IPv4ToString(Span<const uint8_t> a)
556
556
return strprintf (" %u.%u.%u.%u" , a[0 ], a[1 ], a[2 ], a[3 ]);
557
557
}
558
558
559
+ // Return an IPv6 address text representation with zero compression as described in RFC 5952
560
+ // ("A Recommendation for IPv6 Address Text Representation").
559
561
static std::string IPv6ToString (Span<const uint8_t > a)
560
562
{
561
563
assert (a.size () == ADDR_IPV6_SIZE);
562
- // clang-format off
563
- return strprintf (" %x:%x:%x:%x:%x:%x:%x:%x" ,
564
- ReadBE16 (&a[0 ]),
565
- ReadBE16 (&a[2 ]),
566
- ReadBE16 (&a[4 ]),
567
- ReadBE16 (&a[6 ]),
568
- ReadBE16 (&a[8 ]),
569
- ReadBE16 (&a[10 ]),
570
- ReadBE16 (&a[12 ]),
571
- ReadBE16 (&a[14 ]));
572
- // clang-format on
564
+ const std::array groups{
565
+ ReadBE16 (&a[0 ]),
566
+ ReadBE16 (&a[2 ]),
567
+ ReadBE16 (&a[4 ]),
568
+ ReadBE16 (&a[6 ]),
569
+ ReadBE16 (&a[8 ]),
570
+ ReadBE16 (&a[10 ]),
571
+ ReadBE16 (&a[12 ]),
572
+ ReadBE16 (&a[14 ]),
573
+ };
574
+
575
+ // The zero compression implementation is inspired by Rust's std::net::Ipv6Addr, see
576
+ // https://github.com/rust-lang/rust/blob/cc4103089f40a163f6d143f06359cba7043da29b/library/std/src/net/ip.rs#L1635-L1683
577
+ struct ZeroSpan {
578
+ size_t start_index{0 };
579
+ size_t len{0 };
580
+ };
581
+
582
+ // Find longest sequence of consecutive all-zero fields. Use first zero sequence if two or more
583
+ // zero sequences of equal length are found.
584
+ ZeroSpan longest, current;
585
+ for (size_t i{0 }; i < groups.size (); ++i) {
586
+ if (groups[i] != 0 ) {
587
+ current = {i + 1 , 0 };
588
+ continue ;
589
+ }
590
+ current.len += 1 ;
591
+ if (current.len > longest.len ) {
592
+ longest = current;
593
+ }
594
+ }
595
+
596
+ std::string r;
597
+ r.reserve (39 );
598
+ for (size_t i{0 }; i < groups.size (); ++i) {
599
+ // Replace the longest sequence of consecutive all-zero fields with two colons ("::").
600
+ if (longest.len >= 2 && i >= longest.start_index && i < longest.start_index + longest.len ) {
601
+ if (i == longest.start_index ) {
602
+ r += " ::" ;
603
+ }
604
+ continue ;
605
+ }
606
+ r += strprintf (" %s%x" , ((!r.empty () && r.back () != ' :' ) ? " :" : " " ), groups[i]);
607
+ }
608
+
609
+ return r;
573
610
}
574
611
575
612
std::string CNetAddr::ToStringIP () const
0 commit comments