DoxigAlpha

printFloatHex

Function parameters

Parameters

#
w:*Writer
value:anytype
case:std.fmt.Case
opt_precision:?usize

Type definitions in this namespace

Types

#
Allocating
Maintains `Writer` state such that it writes to the unused capacity of an

Writes to `buffer` and returns `error.WriteFailed` when it is full.

Functions

#
fixed
Writes to `buffer` and returns `error.WriteFailed` when it is full.
buffered
Returns the contents not yet drained.
writeVec
If the total number of bytes of `data` fits inside `unusedCapacitySlice`,
writeSplat
If the number of bytes to write based on `data` and `splat` fits inside
writeSplatHeader
Returns how many bytes were consumed from `header` and `data`.
writeSplatHeaderLimit
Equivalent to `writeSplatHeader` but writes at most `limit` bytes.
flush
Drains all remaining buffered data.
defaultFlush
Repeatedly calls `VTable.drain` until `end` is zero.
noopFlush
Does nothing.
writableArray
Asserts the provided buffer has total capacity enough for `len`.
writableSlice
Asserts the provided buffer has total capacity enough for `len`.
writableSliceGreedy
Asserts the provided buffer has total capacity enough for `minimum_len`.
writableSliceGreedyPreserve
Asserts the provided buffer has total capacity enough for `minimum_len`
writableSlicePreserve
Asserts the provided buffer has total capacity enough for `len`.
advance
After calling `writableSliceGreedy`, this function tracks how many bytes
writeVecAll
The `data` parameter is mutable because this function needs to mutate the
writeSplatAll
The `data` parameter is mutable because this function needs to mutate the
writeAll
Calls `drain` as many times as necessary such that all of `bytes` are
print
Renders fmt string with args, calling `writer` with slices of bytes.
writeByte
Calls `drain` as many times as necessary such that `byte` is transferred.
writeBytePreserve
When draining the buffer, ensures that at least `preserve` bytes
splatByteAll
Writes the same byte many times, performing the underlying write call as
splatByte
Writes the same byte many times, allowing short writes.
splatBytesAll
Writes the same slice many times, performing the underlying write call as
splatBytes
Writes the same slice many times, allowing short writes.
writeInt
Asserts the `buffer` was initialized with a capacity of at least `@sizeOf(T)` bytes.
writeStruct
The function is inline to avoid the dead code in case `endian` is
sendFile
Unlike `writeSplat` and `writeVec`, this function will call into `VTable`
sendFileHeader
Returns how many bytes from `header` and `file_reader` were consumed.
sendFileReading
Asserts nonzero buffer capacity and nonzero `limit`.
sendFileAll
Number of bytes logically written is returned.
sendFileReadingAll
Equivalent to `sendFileAll` but uses direct `pread` and `read` calls on
printValue
Asserts `buffer` capacity of at least 2 if `value` is a union.
printIntAny
In general, prefer `printInt` to avoid generic explosion.
printFloat
Uses a larger stack buffer; asserts mode is decimal or scientific.
printFloatHexOptions
Uses a smaller stack buffer; asserts mode is not decimal or scientific.
printByteSize
Format option `precision` is ignored when `value` is less than 1kB
printDuration
Writes number of nanoseconds according to its signed magnitude:
writeUleb128
Write a single unsigned integer as LEB128 to the given writer.
writeSleb128
Write a single signed integer as LEB128 to the given writer.
writeLeb128
Write a single integer as LEB128 to the given writer.
consume
Removes the first `n` bytes from `buffer` by shifting buffer contents,
consumeAll
Shortcut for setting `end` to zero and returning zero.
unimplementedSendFile
For use when the `Writer` implementation can cannot offer a more efficient
fixedDrain
When this function is called it usually means the buffer got full, so it's
Hashed
Provides a `Writer` implementation based on calling `Hasher.update`, sending
Hashing
Provides a `Writer` implementation based on calling `Hasher.update`,

Error sets in this namespace

Error Sets

#

= .{ .vtable = &.{ .drain = failingDrain, .sendFile = failingSendFile, .rebase = failingRebase, }, .buffer = &.{}, }

Values

#
failing
= .{ .vtable = &.{ .drain = failingDrain, .sendFile = failingSendFile, .rebase = failingRebase, }, .buffer = &.{}, }

Source

Implementation

#
pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void {
    const v = switch (@TypeOf(value)) {
        // comptime_float internally is a f128; this preserves precision.
        comptime_float => @as(f128, value),
        else => value,
    };

    if (std.math.signbit(v)) try w.writeByte('-');
    if (std.math.isNan(v)) return w.writeAll(switch (case) {
        .lower => "nan",
        .upper => "NAN",
    });
    if (std.math.isInf(v)) return w.writeAll(switch (case) {
        .lower => "inf",
        .upper => "INF",
    });

    const T = @TypeOf(v);
    const TU = std.meta.Int(.unsigned, @bitSizeOf(T));

    const mantissa_bits = std.math.floatMantissaBits(T);
    const fractional_bits = std.math.floatFractionalBits(T);
    const exponent_bits = std.math.floatExponentBits(T);
    const mantissa_mask = (1 << mantissa_bits) - 1;
    const exponent_mask = (1 << exponent_bits) - 1;
    const exponent_bias = (1 << (exponent_bits - 1)) - 1;

    const as_bits: TU = @bitCast(v);
    var mantissa = as_bits & mantissa_mask;
    var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask));

    const is_denormal = exponent == 0 and mantissa != 0;
    const is_zero = exponent == 0 and mantissa == 0;

    if (is_zero) {
        // Handle this case here to simplify the logic below.
        try w.writeAll("0x0");
        if (opt_precision) |precision| {
            if (precision > 0) {
                try w.writeAll(".");
                try w.splatByteAll('0', precision);
            }
        } else {
            try w.writeAll(".0");
        }
        try w.writeAll("p0");
        return;
    }

    if (is_denormal) {
        // Adjust the exponent for printing.
        exponent += 1;
    } else {
        if (fractional_bits == mantissa_bits)
            mantissa |= 1 << fractional_bits; // Add the implicit integer bit.
    }

    const mantissa_digits = (fractional_bits + 3) / 4;
    // Fill in zeroes to round the fraction width to a multiple of 4.
    mantissa <<= mantissa_digits * 4 - fractional_bits;

    if (opt_precision) |precision| {
        // Round if needed.
        if (precision < mantissa_digits) {
            // We always have at least 4 extra bits.
            var extra_bits = (mantissa_digits - precision) * 4;
            // The result LSB is the Guard bit, we need two more (Round and
            // Sticky) to round the value.
            while (extra_bits > 2) {
                mantissa = (mantissa >> 1) | (mantissa & 1);
                extra_bits -= 1;
            }
            // Round to nearest, tie to even.
            mantissa |= @intFromBool(mantissa & 0b100 != 0);
            mantissa += 1;
            // Drop the excess bits.
            mantissa >>= 2;
            // Restore the alignment.
            mantissa <<= @as(std.math.Log2Int(TU), @intCast((mantissa_digits - precision) * 4));

            const overflow = mantissa & (1 << 1 + mantissa_digits * 4) != 0;
            // Prefer a normalized result in case of overflow.
            if (overflow) {
                mantissa >>= 1;
                exponent += 1;
            }
        }
    }

    // +1 for the decimal part.
    var buf: [1 + mantissa_digits]u8 = undefined;
    assert(std.fmt.printInt(&buf, mantissa, 16, case, .{ .fill = '0', .width = 1 + mantissa_digits }) == buf.len);

    try w.writeAll("0x");
    try w.writeByte(buf[0]);
    const trimmed = std.mem.trimRight(u8, buf[1..], "0");
    if (opt_precision) |precision| {
        if (precision > 0) try w.writeAll(".");
    } else if (trimmed.len > 0) {
        try w.writeAll(".");
    }
    try w.writeAll(trimmed);
    // Add trailing zeros if explicitly requested.
    if (opt_precision) |precision| if (precision > 0) {
        if (precision > trimmed.len)
            try w.splatByteAll('0', precision - trimmed.len);
    };
    try w.writeAll("p");
    try w.printInt(exponent - exponent_bias, 10, case, .{});
}