Logo Wy Online Judge

WyOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#480#106. 「NOIP2024」编辑字符串PigsyyCompile Error//C++2333.5kb2025-04-25 12:27:362025-04-25 12:27:37

answer



#include <limits>
#include <compare>
#include <cstdint>
#include <bit>
#include <format>
#include <cmath>
#include <numbers>
#include <functional>
#include <concepts>
#include <compare>
#include <cinttypes>
#include <cstdlib>
#include <type_traits>
#include <bit>
#include <string>  // TODO
#include <bitset>  // TODO
#include <iostream>

#include <assert.h>

namespace leviathan::math::numeric
{

template <typename T>
struct div_result
{
    T quotient;
    T remainder;

    constexpr div_result(T quot, T rem) : quotient(quot), remainder(rem) { }
    constexpr div_result(std::div_t x) : quotient(x.quot), remainder(x.rem) { }
    constexpr div_result(std::ldiv_t x) : quotient(x.quot), remainder(x.rem) { }
    constexpr div_result(std::lldiv_t x) : quotient(x.quot), remainder(x.rem) { }
    constexpr div_result(std::imaxdiv_t x) : quotient(x.quot), remainder(x.rem) { }
};

template <bool Signed, std::endian Endian>
struct int128_layout
{
    using lower_type = uint64_t;
    using upper_type = std::conditional_t<Signed, int64_t, uint64_t>;

    static constexpr bool lower_index = (Endian == std::endian::little);

    uint64_t m_data[2];
    
    constexpr int128_layout() = default;

    constexpr int128_layout(upper_type upper, lower_type lower) : m_data{ static_cast<uint64_t>(upper), lower } { }

    upper_type upper() const { return static_cast<upper_type>(m_data[1 - lower_index]); }

    lower_type lower() const { return static_cast<lower_type>(m_data[lower_index]); }
};

template <std::endian Endian = std::endian::native> struct uint128;
template <std::endian Endian = std::endian::native> struct int128;

template <std::endian Endian>
class uint128 : int128_layout<false, Endian>
{
    friend class int128<Endian>;

    using base = int128_layout<false, Endian>;

    template <typename T>
    constexpr static uint128 make_uint128_from_float(T v)
    {
        // Undefined behavior if v is NaN or cannot fit into uint128.
        assert(std::isfinite(v) && v >= 0 &&
                (std::numeric_limits<T>::max_exponent <= 128 ||
                v < std::ldexp(static_cast<T>(1), 128)));

        if (v >= std::ldexp(static_cast<T>(1), 64)) 
        {
            const uint64_t hi = static_cast<uint64_t>(std::ldexp(v, -64));
            const uint64_t lo = static_cast<uint64_t>(v - std::ldexp(static_cast<T>(hi), 64));
            return uint128(hi, lo);
        }
        return uint128(0, static_cast<uint64_t>(v));
    }

    template <typename T>
    constexpr static T make_float_from_uint128(uint128 x) 
    { 
        return static_cast<T>(x.lower()) 
             + std::ldexp(static_cast<T>(x.upper()), 64); 
    }

    template <typename Fn>
    constexpr static uint128 bit_op(Fn fn, uint128 u1, uint128 u2)
    {
        const auto hi = fn(u1.upper(), u2.upper());
        const auto lo = fn(u1.lower(), u2.lower());
        return uint128(hi, lo);
    }

public:

    constexpr uint128() = default;
    constexpr uint128(const uint128&) = default;
    constexpr uint128(uint64_t upper, uint64_t lower) : base(upper, lower) { }
    constexpr uint128(int128<Endian> i128) : uint128(static_cast<uint64_t>(i128.upper()), i128.lower()) { }

    // Constructors from unsigned types
    constexpr uint128(uint64_t u) : uint128(0, u) { }
    constexpr uint128(uint32_t u) : uint128(static_cast<uint64_t>(u)) { }
    constexpr uint128(uint16_t u) : uint128(static_cast<uint64_t>(u)) { }
    constexpr uint128(uint8_t u) : uint128(static_cast<uint64_t>(u)) { }

    // Constructors from signed types
    constexpr uint128(int64_t i) : uint128(std::signbit(i) ? std::numeric_limits<uint64_t>::max() : 0, i) { }
    constexpr uint128(int32_t i) : uint128(static_cast<int64_t>(i)) { }
    constexpr uint128(int16_t i) : uint128(static_cast<int64_t>(i)) { }
    constexpr uint128(int8_t i) : uint128(static_cast<int64_t>(i)) { }

    // Constructors from floating types
    constexpr uint128(float f) : uint128(make_uint128_from_float(f)) { }
    constexpr uint128(double d) : uint128(make_uint128_from_float(d)) { }
    constexpr uint128(long double ld) : uint128(make_uint128_from_float(ld)) { }
    
    // Assignment operator from arithmetic types
    constexpr uint128& operator=(uint128 rhs)
    { 
        this->m_data[0] = rhs.m_data[0];
        this->m_data[1] = rhs.m_data[1];
        return *this;
    }

    constexpr uint128& operator=(uint64_t u) { return *this = uint128(u); }
    constexpr uint128& operator=(uint32_t u) { return *this = uint128(u); }
    constexpr uint128& operator=(uint16_t u) { return *this = uint128(u); }
    constexpr uint128& operator=(uint8_t u) { return *this = uint128(u); }

    constexpr uint128& operator=(int64_t i) { return *this = uint128(i); }
    constexpr uint128& operator=(int32_t i) { return *this = uint128(i); }
    constexpr uint128& operator=(int16_t i) { return *this = uint128(i); }
    constexpr uint128& operator=(int8_t i) { return *this = uint128(i); }

    constexpr uint128& operator=(float f) { return *this = uint128(f); }
    constexpr uint128& operator=(double d) { return *this = uint128(d); }
    constexpr uint128& operator=(long double ld) { return *this = uint128(ld); }

    // Conversion operators to other arithmetic types
    constexpr explicit operator bool(this uint128 x) { return x.lower() || x.upper(); }
    
    constexpr explicit operator char(this uint128 x) { return static_cast<char>(x.lower()); }
    constexpr explicit operator wchar_t(this uint128 x) { return static_cast<wchar_t>(x.lower()); }

    constexpr explicit operator char8_t(this uint128 x) { return static_cast<char8_t>(x.lower()); }
    constexpr explicit operator char16_t(this uint128 x) { return static_cast<char16_t>(x.lower()); }
    constexpr explicit operator char32_t(this uint128 x) { return static_cast<char32_t>(x.lower()); }

    constexpr explicit operator int8_t(this uint128 x) { return static_cast<int8_t>(x.lower()); }
    constexpr explicit operator int16_t(this uint128 x) { return static_cast<int16_t>(x.lower()); }
    constexpr explicit operator int32_t(this uint128 x) { return static_cast<int32_t>(x.lower()); }
    constexpr explicit operator int64_t(this uint128 x) { return static_cast<int64_t>(x.lower()); }

    constexpr explicit operator int128<Endian>(this uint128 x) 
    { 
        return int128<Endian>(
            static_cast<int64_t>(x.upper()),
            x.lower()
        );
    }

    constexpr explicit operator uint8_t(this uint128 x) { return static_cast<uint8_t>(x.lower()); }
    constexpr explicit operator uint16_t(this uint128 x) { return static_cast<uint16_t>(x.lower()); }
    constexpr explicit operator uint32_t(this uint128 x) { return static_cast<uint32_t>(x.lower()); }
    constexpr explicit operator uint64_t(this uint128 x) { return static_cast<uint64_t>(x.lower()); }

    constexpr explicit operator float(this uint128 x) { return make_float_from_uint128<float>(x); }
    constexpr explicit operator double(this uint128 x) { return make_float_from_uint128<double>(x); }
    constexpr explicit operator long double(this uint128 x) { return make_float_from_uint128<long double>(x); }

    // Unary operators
    constexpr uint128 operator+(this uint128 x) { return x; }
    
    constexpr uint128 operator-(this uint128 x)  
    {
        const auto hi = ~x.upper() + static_cast<uint64_t>(x.lower() == 0);
        const auto lo = ~x.lower() + 1;
        return uint128(hi, lo);
    }

    constexpr bool operator!(this uint128 x) { return !static_cast<bool>(x); }

    constexpr uint128 operator~(this uint128 x) { return uint128(~x.upper(), ~x.lower()); }

    // Binary operators
    constexpr uint128 operator|(this uint128 lhs, uint128 rhs) { return bit_op(std::bit_or<>(), lhs, rhs); }
    constexpr uint128 operator&(this uint128 lhs, uint128 rhs) { return bit_op(std::bit_and<>(), lhs, rhs); }
    constexpr uint128 operator^(this uint128 lhs, uint128 rhs) { return bit_op(std::bit_xor<>(), lhs, rhs); }

    constexpr uint128 operator+(this uint128 lhs, uint128 rhs) 
    {
        const auto lo = lhs.lower() + rhs.lower();
        const auto carry = (lo < lhs.lower() ? 1 : 0);
        const auto hi = lhs.upper() + rhs.upper() + carry;
        return uint128(hi, lo);
    }

    constexpr uint128 operator-(this uint128 lhs, uint128 rhs) 
    {
        const auto lo = lhs.lower() - rhs.lower();
        const auto carry = (lo <= lhs.lower() ? 0 : 1);
        const auto hi = lhs.upper() - rhs.upper() - carry;
        return uint128(hi, lo);
    }

    constexpr uint128 operator*(this uint128 lhs, uint128 rhs) 
    {
        // We split uint128 into three parts: 
        // High64bit(H64), Low-High32bit(LH32) and Low-Low32bit(LL32)
        // |----------------|--------|--------|
        // 128             64        32       0
        //        H64           LH32     LL32
        //                           L64
        // A * B = 
        // H64(A) * H64(B) => Overflow
        // H64(A) * L64(B) => H64
        // L64(A) * H64(B) => H64
        // L64(A) * L64(B) =    
        //      LH32(A) * LH32(B) => H64
        //      LL32(A) * LH32(B) => H64 or L64
        //      LH32(A) * LL32(B) => H64 or L64
        //      LL32(A) * LL32(B) => L64

        constexpr uint64_t mask = 0xffffffff;   // mask low 64-bit

        const uint64_t ah = lhs.lower() >> 32;
        const uint64_t al = lhs.lower() & mask;

        const uint64_t bh = rhs.lower() >> 32;
        const uint64_t bl = rhs.lower() & mask;
        
        const auto part_hi = lhs.upper() * rhs.lower() // H64(A) * L64(B)
                           + lhs.lower() * rhs.upper() // L64(A) * H64(B)
                           + ah * bh;              // LH32(A) * LH32(B)

        const auto part_lo = al * bl; // LL32(A) * LL32(B)

        uint128 result(part_hi, part_lo);

        result += uint128(ah * bl) << 32;  // LH32(A) * LL32(B)
        result += uint128(bh * al) << 32;  // LL32(A) * LH32(B)

        return result;
    }

    constexpr uint128 operator/(this uint128 lhs, uint128 rhs) { return div_mod(lhs, rhs).quotient; }

    constexpr uint128 operator%(this uint128 lhs, uint128 rhs) { return div_mod(lhs, rhs).remainder; }

    constexpr uint128 operator<<(this uint128 lhs, uint64_t amount) 
    {
        // We use uint64_t instead of int to make amount non-negative.
        // The result is undefined if the right operand is negative, or 
        // greater than or equal to the number of bits in the left expression's type.
        assert(amount < 128 && "");

        const auto hi = lhs.upper();
        const auto lo = lhs.lower();
        
        if (amount >= 64)
        {
            return uint128(lo << (amount - 64), 0);
        }
        else if (amount > 0)
        {
            return uint128((hi << amount) | (lo >> (64 - amount)), lo << amount);
        }
        else
        {
            return lhs;
        }
    }

    constexpr uint128 operator>>(this uint128 lhs, uint64_t amount) 
    {
        // We use uint64_t instead of int to make amount non-negative.
        // The result is undefined if the right operand is negative, or 
        // greater than or equal to the number of bits in the left expression's type.
        assert(amount < 128 && "");

        const auto hi = lhs.upper();
        const auto lo = lhs.lower();

        if (amount >= 64)
        {
            return uint128(0, hi >> (amount - 64));
        }
        else if (amount > 0)
        {
            return uint128(hi >> amount, (lo >> amount) | (hi << (64 - amount)));
        }
        else
        {
            return lhs;
        }
    }

    // Comparision
    constexpr bool operator==(this uint128 lhs, uint128 rhs)  
    { 
        return lhs.lower() == rhs.lower()
            && lhs.upper() == rhs.upper();
    }

    constexpr auto operator<=>(this uint128 lhs, uint128 rhs) 
    {
        return lhs.upper() != rhs.upper()
             ? lhs.upper() <=> rhs.upper()
             : lhs.lower() <=> rhs.lower();
    }

    // Other operators
    constexpr uint128& operator+=(uint128 rhs) { return *this = *this + rhs; }
    constexpr uint128& operator-=(uint128 rhs) { return *this = *this - rhs; }
    constexpr uint128& operator*=(uint128 rhs) { return *this = *this * rhs; }
    constexpr uint128& operator/=(uint128 rhs) { return *this = *this / rhs; }
    constexpr uint128& operator%=(uint128 rhs) { return *this = *this % rhs; }
    constexpr uint128& operator|=(uint128 rhs) { return *this = *this | rhs; }
    constexpr uint128& operator^=(uint128 rhs) { return *this = *this ^ rhs; }
    constexpr uint128& operator&=(uint128 rhs) { return *this = *this & rhs; }

    constexpr uint128& operator<<=(int amount) { return *this = *this << amount; }
    constexpr uint128& operator>>=(int amount) { return *this = *this >> amount; }

    constexpr uint128& operator++() { return *this = *this + 1; }

    constexpr uint128& operator--() { return *this = *this - 1; }

    constexpr uint128 operator++(int)
    {
        auto temp = *this;
        ++*this;
        return temp;
    }

    constexpr uint128 operator--(int)
    {
        auto temp = *this;
        --*this;
        return temp;
    }

    // Bits
    constexpr friend int popcount(uint128 x) 
    {
        return std::popcount(x.lower()) 
             + std::popcount(x.upper());
    }

    friend constexpr bool has_single_bit(uint128 x) { return popcount(x) == 1; }

    friend constexpr int countl_zero(uint128 x) 
    {
        return x.upper() == 0 
             ? std::countl_zero(x.lower()) + 64
             : std::countl_zero(x.upper());
    } 

    friend constexpr int countr_zero(uint128 x) 
    {
        return x.lower() == 0
             ? std::countr_zero(x.upper()) + 64
             : std::countr_zero(x.lower());
    }

    friend constexpr int countl_one(uint128 x) 
    {
        return x.upper() == std::numeric_limits<uint64_t>::max()
             ? std::countl_one(x.lower()) + 64
             : std::countl_one(x.upper());
    }

    friend constexpr int countr_one(uint128 x) 
    {
        return x.lower() == std::numeric_limits<uint64_t>::max()
             ? std::countr_one(x.upper()) + 64
             : std::countr_one(x.lower());
    }

    std::string to_string(this uint128 x) 
    {
        return std::format("{}", x);
    }

    constexpr uint64_t hash_code(this uint128 x)
    {
        return hash_combine(x.upper(), x.lower());
    }

    static consteval uint128 max() 
    { 
        // 11111...11111
        return uint128(
            std::numeric_limits<uint64_t>::max(), 
            std::numeric_limits<uint64_t>::max()
        );
    }

    static consteval uint128 min() { return uint128(0, 0); }

    static constexpr div_result<uint128> div_mod(uint128 dividend, uint128 divisor)
    {
        assert(divisor != 0 && "dividend = quotient * divisor + remainder");

        // https://stackoverflow.com/questions/5386377/division-without-using
        if (divisor > dividend)
        {
            return { uint128(0), dividend };
        }

        if (divisor == dividend)
        {
            return { uint128(1), uint128(0) };
        }
        
        uint128 denominator = divisor;
        uint128 current = 1;
        uint128 answer = 0;

        // Follow may be faster.
        // const int shift = denominator.countl_zero() - dividend.countl_zero() + 1; 
        const int shift = countl_zero(denominator) - countl_zero(dividend) + 1; 
        denominator <<= shift;
        current <<= shift;

        // After loop, the current will be zero.
        for (int i = 0; i <= shift; ++i)
        {
            if (dividend >= denominator)
            {
                dividend -= denominator;
                answer |= current;
            }
            current >>= 1;
            denominator >>= 1;
        }
        
        return { answer, dividend };
    }

    constexpr auto lower() const { return base::lower(); }

    constexpr auto upper() const { return base::upper(); }

};

template <std::endian Endian>
class int128 : int128_layout<true, Endian>
{
    friend class uint128<Endian>;

    using base = int128_layout<true, Endian>;

    template <typename T>
    static constexpr int128 make_int128_from_float(T v)
    {
        // Conversion when v is NaN or cannot fit into int128 would be undefined
        // behavior if using an intrinsic 128-bit integer.
        assert(std::isfinite(v) && (std::numeric_limits<T>::max_exponent <= 127 ||
                                    (v >= -std::ldexp(static_cast<T>(1), 127) &&
                                     v < std::ldexp(static_cast<T>(1), 127))));

        const uint128<Endian> result = signbit(v) ? -uint128<Endian>(-v) : uint128<Endian>(v);
        return static_cast<int128>(result);
    }

    template <typename T>
    static constexpr T make_float_from_int128(int128 x) 
    {
        // We must convert the absolute value and then negate as needed, because
        // floating point types are typically sign-magnitude. Otherwise, the
        // difference between the high and low 64 bits when interpreted as two's
        // complement overwhelms the precision of the mantissa.
        //
        // Also check to make sure we don't negate Int128Min()
        return x.upper() < 0 && x != int128::min()
            ? -static_cast<T>(-x)
            : static_cast<T>(x.lower()) + std::ldexp(static_cast<T>(x.upper()), 64);
    }

    template <typename Fn>
    static constexpr int128 do_as_uint128(Fn fn, int128 x, int128 y)
    {
        const uint128<Endian> ux = x, uy = y;
        return int128(fn(ux, uy));
    }

public:

    constexpr int128() = default;
    constexpr int128(const int128&) = default;
    constexpr int128(int64_t upper, uint64_t lower) : base(upper, lower) { }
    constexpr int128(uint128<Endian> u128) : int128(static_cast<int64_t>(u128.upper()), u128.lower()) { }

    // COnstructors from unsigned types
    constexpr int128(uint64_t u) : int128(0, u) { }
    constexpr int128(uint32_t u) : int128(static_cast<uint64_t>(u)) { }
    constexpr int128(uint16_t u) : int128(static_cast<uint64_t>(u)) { }
    constexpr int128(uint8_t u) : int128(static_cast<uint64_t>(u)) { }

    // Constructors from signed types
    constexpr int128(int64_t i) : int128((std::signbit(i) ? ~int64_t(0) : 0), static_cast<uint64_t>(i)) { }
    constexpr int128(int32_t i) : int128(static_cast<int64_t>(i)) { }
    constexpr int128(int16_t i) : int128(static_cast<int64_t>(i)) { }
    constexpr int128(int8_t i) : int128(static_cast<int64_t>(i)) { }

    // Constructors from floating types
    constexpr int128(float f) : int128(make_int128_from_float(f)) { }
    constexpr int128(double d) : int128(make_int128_from_float(d)) { }
    constexpr int128(long double ld) : int128(make_int128_from_float(ld)) { }

    constexpr int128& operator=(int128 rhs)
    {
        this->m_data[0] = rhs.m_data[0];
        this->m_data[1] = rhs.m_data[1];
        return *this;
    }

    constexpr int128& operator=(uint64_t u) { return *this = int128(u); }
    constexpr int128& operator=(uint32_t u) { return *this = int128(u); }
    constexpr int128& operator=(uint16_t u) { return *this = int128(u); }
    constexpr int128& operator=(uint8_t u) { return *this = int128(u); }

    constexpr int128& operator=(int64_t i) { return *this = int128(i); }
    constexpr int128& operator=(int32_t i) { return *this = int128(i); }
    constexpr int128& operator=(int16_t i) { return *this = int128(i); }
    constexpr int128& operator=(int8_t i) { return *this = int128(i); }

    constexpr int128& operator=(float f) { return *this = int128(f); }
    constexpr int128& operator=(double d) { return *this = int128(d); }
    constexpr int128& operator=(long double ld) { return *this = int128(ld); }

    // Conversion operators to other arithmetic types
    constexpr explicit operator bool(this int128 x) { return x.upper() || x.lower(); }
    
    constexpr explicit operator char(this int128 x) { return static_cast<char>(static_cast<int64_t>(x)); }
    constexpr explicit operator wchar_t(this int128 x) { return static_cast<wchar_t>(static_cast<int64_t>(x)); }

    constexpr explicit operator char8_t(this int128 x) { return static_cast<char8_t>(x.lower()); }
    constexpr explicit operator char16_t(this int128 x) { return static_cast<char16_t>(x.lower()); }
    constexpr explicit operator char32_t(this int128 x) { return static_cast<char32_t>(x.lower()); }

    constexpr explicit operator int8_t(this int128 x) { return static_cast<int8_t>(static_cast<int64_t>(x)); }
    constexpr explicit operator int16_t(this int128 x) { return static_cast<int16_t>(static_cast<int64_t>(x)); }
    constexpr explicit operator int32_t(this int128 x) { return static_cast<int32_t>(static_cast<int64_t>(x)); }
    constexpr explicit operator int64_t(this int128 x) { return static_cast<int64_t>(x.lower()); }

    constexpr explicit operator uint8_t(this int128 x) { return static_cast<uint8_t>(x.lower()); }
    constexpr explicit operator uint16_t(this int128 x) { return static_cast<uint16_t>(x.lower()); }
    constexpr explicit operator uint32_t(this int128 x) { return static_cast<uint32_t>(x.lower()); }
    constexpr explicit operator uint64_t(this int128 x) { return static_cast<uint64_t>(x.lower()); }

    constexpr explicit operator uint128<Endian>(this int128 x) 
    {
        return uint128<Endian>(
            static_cast<int64_t>(x.upper()),
            x.lower()
        );
    }

    constexpr explicit operator float(this int128 x) { return make_float_from_int128<float>(x); }
    constexpr explicit operator double(this int128 x) { return make_float_from_int128<double>(x); }
    constexpr explicit operator long double(this int128 x) { return make_float_from_int128<long double>(x); }

    // Unary operators
    constexpr int128 operator+(this int128 x) { return x; }

    constexpr int128 operator-(this int128 x) 
    {
        const uint128<Endian> u = x;
        return -u;
    }

    constexpr bool operator!(this int128 x) { return !static_cast<bool>(x); }

    constexpr int128 operator~(this int128 x) { return int128(~x.upper(), ~x.lower()); }

    // Binary operators
    constexpr int128 operator|(this int128 lhs, int128 rhs) { return do_as_uint128(std::bit_or<>(), lhs, rhs); }
    constexpr int128 operator&(this int128 lhs, int128 rhs) { return do_as_uint128(std::bit_and<>(), lhs, rhs); }
    constexpr int128 operator^(this int128 lhs, int128 rhs) { return do_as_uint128(std::bit_xor<>(), lhs, rhs); }

    constexpr int128 operator+(this int128 lhs, int128 rhs) { return do_as_uint128(std::plus<>(), lhs, rhs); }

    constexpr int128 operator-(this int128 lhs, int128 rhs) { return do_as_uint128(std::minus<>(), lhs, rhs); }

    constexpr int128 operator*(this int128 lhs, int128 rhs) { return do_as_uint128(std::multiplies<>(), lhs, rhs); }
    
    constexpr int128 operator/(this int128 lhs, int128 rhs) { return div_mod(lhs, rhs).quotient; }

    constexpr int128 operator%(this int128 lhs, int128 rhs) { return div_mod(lhs, rhs).remainder; }

    constexpr int128 operator<<(this int128 lhs, uint64_t amount) 
    {
        // We use uint64_t instead of int to make amount non-negative.
        // The result is undefined if the right operand is negative, or 
        // greater than or equal to the number of bits in the left expression's type.
        assert(amount < 128 && "");
        
        // The shift operation in signed integer and unsigned are same.
        return static_cast<uint128<Endian>>(lhs) << amount;
    }

    // The only difference between signed and unsigned is right shift operation.
    constexpr int128 operator>>(this int128 lhs, uint64_t amount) 
    {
        // We use uint64_t instead of int to make amount non-negative.
        // The result is undefined if the right operand is negative, or 
        // greater than or equal to the number of bits in the left expression's type.
        assert(amount < 128 && "");

        const auto result = static_cast<uint128<Endian>>(lhs) >> amount;
        // Right-shift on signed integral types is an arithmetic right shift, 
        // which performs sign-extension. So we must keep sign bit when shifting 
        // signed integer.
        if (signbit(lhs.upper()))
        {
            return result | (uint128<Endian>::max() << (127 - amount));
        }
        return result;
    }

    constexpr bool operator==(this int128 lhs, int128 rhs) 
    {
        return lhs.upper() == rhs.upper()
            && lhs.lower() == rhs.lower();
    }

    constexpr auto operator<=>(this int128 lhs, int128 rhs) 
    {
        return lhs.upper() == rhs.upper()
             ? lhs.lower() <=> rhs.lower()
             : lhs.upper() <=> rhs.upper();
    }

    // Other operators
    constexpr int128& operator+=(int128 rhs) { return *this = *this + rhs; }
    constexpr int128& operator-=(int128 rhs) { return *this = *this - rhs; }
    constexpr int128& operator*=(int128 rhs) { return *this = *this * rhs; }
    constexpr int128& operator/=(int128 rhs) { return *this = *this / rhs; }
    constexpr int128& operator%=(int128 rhs) { return *this = *this % rhs; }
    constexpr int128& operator|=(int128 rhs) { return *this = *this | rhs; }
    constexpr int128& operator^=(int128 rhs) { return *this = *this ^ rhs; }
    constexpr int128& operator&=(int128 rhs) { return *this = *this & rhs; }

    constexpr int128& operator<<=(int amount) { return *this = *this << amount; }
    constexpr int128& operator>>=(int amount) { return *this = *this >> amount; }

    constexpr int128& operator++() { return *this = *this + 1; }

    constexpr int128& operator--() { return *this = *this - 1; }

    constexpr int128 operator++(int)
    {
        auto temp = *this;
        ++*this;
        return temp;
    }

    constexpr int128 operator--(int)
    {
        auto temp = *this;
        --*this;
        return temp;
    }

    constexpr size_t hash_code(this int128 x)
    {
        return hash_combine(x.upper(), x.lower());
    }

    static consteval int128 max() 
    { 
        // 0111111...111
        return int128(
            std::numeric_limits<int64_t>::max(),
            std::numeric_limits<uint64_t>::max()
        );
    }

    static consteval int128 min()
    {
        // 1000000...000
        return int128(
            std::numeric_limits<int64_t>::min(),
            0
        );
    }

    static constexpr div_result<int128> div_mod(int128 dividend, int128 divisor)
    {
        assert(dividend != int128::min() || divisor != -1);

        const uint128<Endian> quotient = dividend < 0 ? -uint128<Endian>(dividend) : uint128<Endian>(dividend);
        const uint128<Endian> remainder = divisor < 0 ? -uint128<Endian>(divisor) : uint128<Endian>(divisor);

        const auto [quot, rem] = uint128<Endian>::div_mod(quotient, remainder);

        return { static_cast<int128>(quot), static_cast<int128>(rem) };
    }

    std::string to_string(this int128 x)
    {
        return std::format("{}", x);
    } 

    constexpr auto lower() const { return base::lower(); }

    constexpr auto upper() const { return base::upper(); }
};

using int128_t = int128<>;
using uint128_t = uint128<>;
// template class uint128<>;
// template class int128<>;

template <std::endian Endian>
std::ostream& operator<<(std::ostream& os, uint128<Endian> x)
{
    return os << x.to_string();
}

template <std::endian Endian>
std::ostream& operator<<(std::ostream& os, int128<Endian> x)
{
    return os << x.to_string();
}

}

// Specialize for std::numeric_limits
template <std::endian Endian>
struct std::numeric_limits<leviathan::math::numeric::uint128<Endian>>
{
private:
    using uint128 = leviathan::math::numeric::uint128<Endian>;

public:
    static constexpr bool is_specialized = true;
    static constexpr bool is_signed = false;
    static constexpr bool is_integer = true;
    static constexpr bool is_exact = true;
    static constexpr bool has_infinity = false;
    static constexpr bool has_quiet_NaN = false;
    static constexpr bool has_signaling_NaN = false;
    static constexpr std::float_denorm_style has_denorm = std::float_denorm_style::denorm_absent;
    static constexpr bool has_denorm_loss = false;
    static constexpr std::float_round_style round_style = std::float_round_style::round_toward_zero;
    static constexpr bool is_iec559 = false;
    static constexpr bool is_bounded = true;
    static constexpr bool is_modulo = true;
    static constexpr int digits = 128;
    static constexpr int digits10 = 38;
    static constexpr int max_digits10 = 0;
    static constexpr int radix = 2;
    static constexpr int min_exponent = 0;
    static constexpr int min_exponent10 = 0;
    static constexpr int max_exponent = 0;
    static constexpr int max_exponent10 = 0;

    static constexpr bool traps = std::numeric_limits<uint64_t>::traps;
    static constexpr bool tinyness_before = false;

    static constexpr uint128 min() { return uint128::min(); }
    static constexpr uint128 lowest() { return 0; }
    static constexpr uint128 max() { return uint128::max(); }
    static constexpr uint128 epsilon() { return 0; }
    static constexpr uint128 round_error() { return 0; }
    static constexpr uint128 infinity() { return 0; }
    static constexpr uint128 quiet_NaN() { return 0; }
    static constexpr uint128 signaling_NaN() { return 0; }
    static constexpr uint128 denorm_min() { return 0; }
};

template <std::endian Endian>
struct std::numeric_limits<leviathan::math::numeric::int128<Endian>>
{
private:
    using int128 = leviathan::math::numeric::int128<Endian>;

public:

    static constexpr bool is_specialized = true;
    static constexpr bool is_signed = true;
    static constexpr bool is_integer = true;
    static constexpr bool is_exact = true;
    static constexpr bool has_infinity = false;
    static constexpr bool has_quiet_NaN = false;
    static constexpr bool has_signaling_NaN = false;
    static constexpr std::float_denorm_style has_denorm = std::float_denorm_style::denorm_absent;
    static constexpr bool has_denorm_loss = false;
    static constexpr std::float_round_style round_style = std::float_round_style::round_toward_zero;
    static constexpr bool is_iec559 = false;
    static constexpr bool is_bounded = true;
    static constexpr bool is_modulo = false;
    static constexpr int digits = 127;
    static constexpr int digits10 = 38;
    static constexpr int max_digits10 = 0;
    static constexpr int radix = 2;
    static constexpr int min_exponent = 0;
    static constexpr int min_exponent10 = 0;
    static constexpr int max_exponent = 0;
    static constexpr int max_exponent10 = 0;
    static constexpr bool traps = numeric_limits<uint64_t>::traps;
    static constexpr bool tinyness_before = false;

    static constexpr int128 min() { return int128::min(); }
    static constexpr int128 lowest() { return int128::min(); }
    static constexpr int128 max() { return int128::max(); }
    static constexpr int128 epsilon() { return 0; }
    static constexpr int128 round_error() { return 0; }
    static constexpr int128 infinity() { return 0; }
    static constexpr int128 quiet_NaN() { return 0; }
    static constexpr int128 signaling_NaN() { return 0; }
    static constexpr int128 denorm_min() { return 0; }
};

// Specialize for std::hash
template <std::endian Endian>
struct std::hash<leviathan::math::numeric::uint128<Endian>> 
{
    static constexpr auto operator()(leviathan::math::numeric::uint128<Endian> x)
    {
        return x.hash_code();
    }
};

template <std::endian Endian>
struct std::hash<leviathan::math::numeric::int128<Endian>> 
{
    static constexpr auto operator()(leviathan::math::numeric::int128<Endian> x)
    {
        return x.hash_code();
    }
};

// Specialize for std::formatter
template <std::endian Endian, typename CharT>
struct std::formatter<leviathan::math::numeric::uint128<Endian>, CharT>
{
    using uint128 = leviathan::math::numeric::uint128<Endian>;

    template <typename ParseContext>
    constexpr typename ParseContext::iterator parse(ParseContext& ctx) 
    {
        return m_fmt.parse(ctx);
    }

    template <typename FormatContext>
    typename FormatContext::iterator format(uint128 x, FormatContext& ctx) const
    {
        unsigned __int128 v = (static_cast<unsigned __int128>(x.upper()) << 64) 
                            | (static_cast<unsigned __int128>(x.lower()));
        return m_fmt.format(v, ctx);
    }   

    std::formatter<unsigned __int128, CharT> m_fmt;
};

template <std::endian Endian, typename CharT>
struct std::formatter<leviathan::math::numeric::int128<Endian>, CharT>
{
    using int128 = leviathan::math::numeric::int128<Endian>;

    template <typename ParseContext>
    constexpr typename ParseContext::iterator parse(ParseContext& ctx) 
    {
        return m_fmt.parse(ctx);
    }

    template <typename FormatContext>
    typename FormatContext::iterator format(int128 x, FormatContext& ctx) const
    {
        signed __int128 v = (static_cast<signed __int128>(x.upper()) << 64) 
                          | (static_cast<signed __int128>(x.lower()));
        return m_fmt.format(v, ctx);
    }   

    std::formatter<signed __int128, CharT> m_fmt;
};

namespace leviathan
{

using leviathan::math::numeric::uint128_t;
using leviathan::math::numeric::int128_t;

}


int main()
{

}







详细

answer.code:7:10: fatal error: format: No such file or directory
    7 | #include <format>
      |          ^~~~~~~~
compilation terminated.