toRadixString method

String toRadixString({
  1. int radix = 2,
  2. int chunkSize = 4,
  3. bool leadingZeros = false,
  4. bool includeWidth = true,
  5. String sepChar = '_',
})

Return the radix encoding of the current LogicValue as a sequence of radix characters. By default, the output is prefixed by the length and encoding format: <len>'<format><encoded-value>.

If includeWidth is false, the length and encoding format are omitted. The resulting string is not self-describing and cannot be parsed by ofRadixString without restoring that information.

ofRadixString can parse a decorated String produced by toRadixString and construct a LogicValue.

Here is the number 1492 printed as a radix string:

  • Binary: 15'b101_1101_0100
  • Quaternary: 15'q11_3110
  • Octal: 15'o2724
  • Decimal: 10'd1492
  • Hex: 15'h05d4

Separators are output according to chunkSize starting from the LSB(right), default is 4 characters. The default separator is '_'. sepChar can be set to another character, but not in radixStringChars, or to an empty string to disable separators. Otherwise, it will throw an exception.

  • chunkSize = default: 61'h2_9ebc_5f06_5bf7
  • chunkSize = 10: 61'h29e_bc5f065bf7

leadingZeros defaults to false, so leading 0s are omitted in the output string:

  • 25'h1 otherwise if leadingZeros is set to true then the output string is:
  • 25'h000_0001

When a LogicValue has 'x' or 'z' bits, then the radix characters those bits overlap will be expanded into binary form with '<' '>' bracketing them as follows:

  • 35'h7_ZZZZ_Z<zzz0><100z>Z Such a LogicValue cannot be converted to a Decimal (10) radix string and will throw an exception.

If the leading bits are 'z', then the output radix character is 'Z' no matter what the length. When leading, 'Z' indicates one or more 'z' bits to fill the first radix character.

  • 9'bz_zzzz_zzzz = 9'hZZZ

Implementation

String toRadixString({
  int radix = 2,
  int chunkSize = 4,
  bool leadingZeros = false,
  bool includeWidth = true,
  String sepChar = '_',
}) {
  if (sepChar.isNotEmpty && radixStringChars.contains(sepChar)) {
    throw LogicValueConversionException('separation character invalid');
  }
  final radixStr = switch (radix) {
    2 => "'b",
    4 => "'q",
    8 => "'o",
    10 => "'d",
    16 => "'h",
    _ => throw LogicValueConversionException('Unsupported radix: $radix'),
  };
  final String reversedStr;
  if (radix == 10) {
    if (isValid) {
      var radixString =
          toBigInt().toUnsigned(width).toRadixString(radix).toUpperCase();
      if (leadingZeros) {
        final span = math.max(
          1,
          (width * math.log(2) / math.log(radix)).floor(),
        );
        for (var i = radixString.length; i < (width / span).ceil(); i++) {
          radixString = '0$radixString';
        }
      }
      reversedStr = _reverse(radixString);
    } else {
      final span = math.max(
        1,
        (width * math.log(2) / math.log(radix)).floor(),
      );
      if (toRadixString().contains(RegExp('[xX]'))) {
        reversedStr = 'X' * span;
      } else {
        reversedStr = 'Z' * span;
      }
    }
  } else {
    final span = (math.log(radix) / math.log(2)).ceil();
    final extendedStr = LogicValue.of(
      this,
      width: span * (width / span).ceil(),
    );
    final buf = StringBuffer();
    var haveLeadingZeros = true;
    for (var i = (extendedStr.width ~/ span) - 1; i >= 0; i--) {
      final binaryChunk = extendedStr.slice((i + 1) * span - 1, i * span);
      var chunkString = binaryChunk.toString(includeWidth: false);
      if (i == extendedStr.width ~/ span - 1) {
        final chunkWidth = chunkString.length;
        chunkString = chunkString.substring(
          chunkWidth - (width - i * span),
          chunkWidth,
        );
      }
      final s = [
        if (chunkString == 'z' * chunkString.length)
          if (span == 1) 'z' else 'Z'
        else if (chunkString == 'x' * chunkString.length)
          if (span == 1) 'x' else 'X'
        else if (chunkString.contains('z') | chunkString.contains('x'))
          '>${_reverse(chunkString)}<'
        else
          binaryChunk.toBigInt().toUnsigned(span).toRadixString(radix),
      ].first;
      if (s != '0') {
        haveLeadingZeros = false;
      }
      if ((s == '0') & !leadingZeros & haveLeadingZeros) {
        continue;
      }
      buf.write(_reverse(s));
    }
    reversedStr = _reverse(buf.toString());
  }

  final spaceString = _reverse(
    reversedStr
        .replaceAllMapped(
          RegExp('((>(.){$chunkSize}<)|([a-zA-Z0-9])){$chunkSize}'),
          (match) => '${match.group(0)}$sepChar',
        )
        .replaceAll('$sepChar<', '<'),
  );

  final fullString = (spaceString.isNotEmpty)
      ? (spaceString[0] == sepChar)
          ? spaceString.substring(1, spaceString.length)
          : spaceString
      : '0';
  return '${includeWidth ? '$width$radixStr' : ''}$fullString';
}