Repository: LadybirdBrowser/ladybird
File: AK/IPv6Address.h (C/C++)

Code before:
#include <AK/StringView.h>
#include <AK/Vector.h>

namespace AK {

class [[gnu::packed]] IPv6Address {
public:
    using in6_addr_t = u8[16];

    constexpr IPv6Address() = default;

    constexpr IPv6Address(in6_addr_t const& data)
    {
        for (size_t i = 0; i < 16; i++)
            m_data[i] = data[i];
    }

    constexpr IPv6Address(Array<u8, 16> const& data)
    {
        for (size_t i = 0; i < 16; i++)
            m_data[i] = data[i];
    }

    constexpr IPv6Address(Array<u16, 8> const& data)
    {
        u16* pieces = reinterpret_cast<u16*>(m_data);
        for (size_t i = 0; i < 8; i++)
            pieces[i] = bit_cast<u16>(NetworkOrdered<u16>(data[i]));
    }

    template<SameAs<char const*> T>
    constexpr IPv6Address(T const&) = delete; // Disable implicit conversion of char const* -> ipv4 -> ipv6

    constexpr IPv6Address(IPv4Address const& ipv4_address)
    {
        // IPv4 mapped IPv6 address
        m_data[10] = 0xff;
        m_data[11] = 0xff;
        m_data[12] = ipv4_address[0];
        m_data[13] = ipv4_address[1];
        m_data[14] = ipv4_address[2];
        m_data[15] = ipv4_address[3];
    }

    constexpr u16 operator[](size_t i) const { return piece(i); }

    ErrorOr<String> to_string() const
    {
        if (is_zero()) {
            return "::"_string;
        }

Review comment (performance):
Sorry for the delay! Only comment is that this reinterpret cast is UB and we should do the shift approach instead.

On your question of:
> The underlying data could also be changed to Array<u16, 8> to better match the spec. I can make the change if you think this is worth doing.

I think it's okay as is. Eventually this will end up diverging away from the exact spec text anyway, as I expect our very unoptimized URL parsing will be optimized at some stage going forward

Code after:
#include <AK/StringView.h>
#include <AK/Vector.h>

namespace AK {

class [[gnu::packed]] IPv6Address {
public:
    using in6_addr_t = u8[16];

    constexpr IPv6Address() = default;

    constexpr IPv6Address(in6_addr_t const& data)
    {
        for (size_t i = 0; i < 16; i++)
            m_data[i] = data[i];
    }

    constexpr IPv6Address(Array<u8, 16> const& data)
    {
        for (size_t i = 0; i < 16; i++)
            m_data[i] = data[i];
    }

    constexpr IPv6Address(Array<u16, 8> const& data)
    {
        for (size_t i = 0; i < 8; i++) {
            auto piece = data[i];
            m_data[2 * i] = static_cast<u8>(piece >> 8);
            m_data[(2 * i) + 1] = static_cast<u8>(piece & 0xff);
        }
    }

    template<SameAs<char const*> T>
    constexpr IPv6Address(T const&) = delete; // Disable implicit conversion of char const* -> ipv4 -> ipv6

    constexpr IPv6Address(IPv4Address const& ipv4_address)
    {
        // IPv4 mapped IPv6 address
        m_data[10] = 0xff;
        m_data[11] = 0xff;
        m_data[12] = ipv4_address[0];
        m_data[13] = ipv4_address[1];
        m_data[14] = ipv4_address[2];
        m_data[15] = ipv4_address[3];
    }

    constexpr u16 operator[](size_t i) const { return piece(i); }

    ErrorOr<String> to_string() const
    {
        if (is_zero()) {