Livt packages

Livt.Base

Version 1.2.1

Foundational bit, array, string, conversion, formatting, and timing helpers for Livt hardware designs.

Published files (32)

src/Format.lvt

namespace Livt.Format

/**
 * Fixed-width string formatting helpers for machine values.
 *
 * The returned strings have compile-time-known lengths for fixed-size output
 * APIs such as UART transmit helpers. Decimal output is zero-padded. Signed
 * decimal output uses a leading sign.
 */
component Format
{
	// Owned decimal workspace; callers serialize formatting operations.
	decimalDigits: byte[10]
	places: uint[10]

	/**
	 * Initializes constant decimal places without division circuitry.
	 */
	new()
	{
		places[0] = 1000000000 as uint
		places[1] = 100000000 as uint
		places[2] = 10000000 as uint
		places[3] = 1000000 as uint
		places[4] = 100000 as uint
		places[5] = 10000 as uint
		places[6] = 1000 as uint
		places[7] = 100 as uint
		places[8] = 10 as uint
		places[9] = 1 as uint
	}

	/**
	 * Extracts ten digits using at most nine scheduled subtractions per place.
	 * Supports the full uint domain; each request overwrites all digit storage.
	 */
	fn EncodeDecimal(value: uint)
	{
		var remaining = value
		for (var index = 0; index < 10; index++) {
			var place = places[index]
			var digit = 0
			while (remaining >= place) {
				state {
					remaining = remaining - place
					digit++
				}
			}
			decimalDigits[index] = (0x30 + digit) as byte
		}
	}

	/**
	 * Returns the ASCII digit for value in 0..9.
	 * Values outside 0..9 return '?'.
	 */
	fn Digit(value: int) byte
	{
		if (value < 0) {
			return 0x3F
		}

		if (value > 9) {
			return 0x3F
		}

		var ascii: int = 0x30 + value
		return ascii as byte
	}

	/**
	 * Returns the uppercase ASCII hex digit for value in 0..15.
	 * Values outside 0..15 return '?'.
	 */
	fn HexDigit(value: int) byte
	{
		if (value < 0) {
			return 0x3F
		}

		if (value < 10) {
			var digit: int = 0x30 + value
			return digit as byte
		}

		if (value < 16) {
			var letter: int = 0x41 + value - 10
			return letter as byte
		}

		return 0x3F
	}

	/**
	 * Formats a byte as three zero-padded decimal digits.
	 * Examples: 0 -> "000", 7 -> "007", 42 -> "042", 255 -> "255".
	 */
	public fn ToStringByte(value: byte) string[3]
	{
		this.EncodeDecimal(value as uint)
		var buf: byte[3]
		for (var index = 0; index < 3; index++) {
			buf[index] = decimalDigits[index + 7]
		}
		return buf.Decode()
	}

	/**
	 * Formats an int as a sign plus ten zero-padded decimal digits.
	 * Examples: 42 -> "+0000000042", -42 -> "-0000000042".
	 *
	 * Supports the full signed int domain, including its minimum value.
	 */
	public fn ToStringInt(value: int) string[11]
	{
		var magnitude = value as uint
		var buf: byte[11]
		buf[0] = 0x2B
		if (value < 0) {
			buf[0] = 0x2D
			magnitude = (0 as uint) - magnitude
		}
		this.EncodeDecimal(magnitude)
		for (var index = 0; index < 10; index++) {
			buf[index + 1] = decimalDigits[index]
		}
		return buf.Decode()
	}

	/**
	 * Formats a uint as ten zero-padded decimal digits.
	 * Examples: 42 -> "0000000042", 255 -> "0000000255".
	 */
	public fn ToStringUInt(value: uint) string[10]
	{
		this.EncodeDecimal(value)
		var buf: byte[10]
		for (var index = 0; index < 10; index++) {
			buf[index] = decimalDigits[index]
		}
		return buf.Decode()
	}

	/**
	 * Formats a byte as two uppercase hexadecimal digits.
	 * Example: 0xAF -> "AF".
	 */
	public fn ToHexByte(value: byte) string[2]
	{
		var n: int = value as int
		var hi: int = (n >> 4) & 15
		var lo: int = n & 15
		var buf: byte[2]
		buf[0] = this.HexDigit(hi)
		buf[1] = this.HexDigit(lo)
		return buf.Decode()
	}

	/**
	 * Formats a byte as eight binary digits.
	 * Example: 0x05 -> "00000101".
	 */
	public fn ToBinaryByte(value: byte) string[8]
	{
		var n: int = value as int
		var buf: byte[8]
		buf[0] = this.Digit((n >> 7) & 1)
		buf[1] = this.Digit((n >> 6) & 1)
		buf[2] = this.Digit((n >> 5) & 1)
		buf[3] = this.Digit((n >> 4) & 1)
		buf[4] = this.Digit((n >> 3) & 1)
		buf[5] = this.Digit((n >> 2) & 1)
		buf[6] = this.Digit((n >> 1) & 1)
		buf[7] = this.Digit(n & 1)
		return buf.Decode()
	}
}