const std = @import("std");
const math = std.math;
const common = @import("common.zig");
const FloatInfo = @import("FloatInfo.zig");
const Number = common.Number;
const floatFromU64 = common.floatFromU64;
fn isFastPath(comptime T: type, n: Number(T)) bool {
    const info = FloatInfo.from(T);
    return info.min_exponent_fast_path <= n.exponent and
        n.exponent <= info.max_exponent_fast_path_disguised and
        n.mantissa <= info.max_mantissa_fast_path and
        !n.many_digits;
}
fn fastPow10(comptime T: type, i: usize) T {
    return switch (T) {
        f16 => ([8]f16{
            1e0, 1e1, 1e2, 1e3, 1e4, 0, 0, 0,
        })[i & 7],
        f32 => ([16]f32{
            1e0, 1e1, 1e2,  1e3, 1e4, 1e5, 1e6, 1e7,
            1e8, 1e9, 1e10, 0,   0,   0,   0,   0,
        })[i & 15],
        f64 => ([32]f64{
            1e0,  1e1,  1e2,  1e3,  1e4,  1e5,  1e6,  1e7,
            1e8,  1e9,  1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
            1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0,
            0,    0,    0,    0,    0,    0,    0,    0,
        })[i & 31],
        f128 => ([64]f128{
            1e0,  1e1,  1e2,  1e3,  1e4,  1e5,  1e6,  1e7,
            1e8,  1e9,  1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
            1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 1e23,
            1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30, 1e31,
            1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
            1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47,
            1e48, 0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,
        })[i & 63],
        else => unreachable,
    };
}
fn fastIntPow10(comptime T: type, i: usize) T {
    return switch (T) {
        u64 => ([16]u64{
            1,             10,             100,             1000,
            10000,         100000,         1000000,         10000000,
            100000000,     1000000000,     10000000000,     100000000000,
            1000000000000, 10000000000000, 100000000000000, 1000000000000000,
        })[i],
        u128 => ([35]u128{
            1,                                   10,
            100,                                 1000,
            10000,                               100000,
            1000000,                             10000000,
            100000000,                           1000000000,
            10000000000,                         100000000000,
            1000000000000,                       10000000000000,
            100000000000000,                     1000000000000000,
            10000000000000000,                   100000000000000000,
            1000000000000000000,                 10000000000000000000,
            100000000000000000000,               1000000000000000000000,
            10000000000000000000000,             100000000000000000000000,
            1000000000000000000000000,           10000000000000000000000000,
            100000000000000000000000000,         1000000000000000000000000000,
            10000000000000000000000000000,       100000000000000000000000000000,
            1000000000000000000000000000000,     10000000000000000000000000000000,
            100000000000000000000000000000000,   1000000000000000000000000000000000,
            10000000000000000000000000000000000,
        })[i],
        else => unreachable,
    };
}
pub fn convertFast(comptime T: type, n: Number(T)) ?T {
    const MantissaT = common.mantissaType(T);
    if (!isFastPath(T, n)) {
        return null;
    }
    
    const info = FloatInfo.from(T);
    var value: T = 0;
    if (n.exponent <= info.max_exponent_fast_path) {
        
        value = @intToFloat(T, n.mantissa);
        value = if (n.exponent < 0)
            value / fastPow10(T, @intCast(usize, -n.exponent))
        else
            value * fastPow10(T, @intCast(usize, n.exponent));
    } else {
        
        const shift = n.exponent - info.max_exponent_fast_path;
        const mantissa = math.mul(MantissaT, n.mantissa, fastIntPow10(MantissaT, @intCast(usize, shift))) catch return null;
        if (mantissa > info.max_mantissa_fast_path) {
            return null;
        }
        value = @intToFloat(T, mantissa) * fastPow10(T, info.max_exponent_fast_path);
    }
    if (n.negative) {
        value = -value;
    }
    return value;
}