From e554d04151a3a09fb0c08e6e0a25ffb6838a582c Mon Sep 17 00:00:00 2001 From: Lukas Renggli Date: Wed, 27 Sep 2023 21:18:10 +0200 Subject: [PATCH] Support different precision for unit measures in human number printing. Add test cases from https://programming.guide/java/formatting-byte-size-to-human-readable-format.html. --- lib/src/printer/number/human.dart | 50 ++++++++++++++++++++++--------- test/printer_test.dart | 50 +++++++++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 16 deletions(-) diff --git a/lib/src/printer/number/human.dart b/lib/src/printer/number/human.dart index 8d19db80..51c62e36 100644 --- a/lib/src/printer/number/human.dart +++ b/lib/src/printer/number/human.dart @@ -90,9 +90,21 @@ class HumanNumberPrinter extends Printer { this.sign, this.unitBase = 10, this.unitOffset = 0, + this.unitPrecision = 0, this.unitPrefix = false, this.unitSeparator = ' ', - }) : _mantissa = FixedNumberPrinter( + }) : _unit = FixedNumberPrinter( + base: base, + characters: characters, + delimiter: delimiter, + infinity: infinity, + nan: nan, + padding: padding, + precision: unitPrecision, + separator: separator, + sign: sign ?? const SignNumberPrinter.omitPositiveSign(), + ), + _scaled = FixedNumberPrinter( base: base, characters: characters, delimiter: delimiter, @@ -119,11 +131,12 @@ class HumanNumberPrinter extends Printer { int precision = 0, String separator = '', Printer? sign, + int unitPrecision = 0, bool unitPrefix = false, String unitSeparator = ' ', }) => HumanNumberPrinter( - base: base = 10, + base: base, characters: characters, delimiter: delimiter, infinity: infinity, @@ -132,10 +145,11 @@ class HumanNumberPrinter extends Printer { precision: precision, separator: separator, sign: sign, - unitPrefix: unitPrefix, - unitSeparator: unitSeparator, unitBase: decimalUnitBase, unitOffset: decimalUnitOffset, + unitPrecision: unitPrecision, + unitPrefix: unitPrefix, + unitSeparator: unitSeparator, units: long ? decimalUnitsLong : decimalUnitsShort, ); @@ -153,6 +167,7 @@ class HumanNumberPrinter extends Printer { int padding = 0, int precision = 0, String separator = '', + int unitPrecision = 0, Printer? sign, bool unitPrefix = false, String unitSeparator = ' ', @@ -167,9 +182,11 @@ class HumanNumberPrinter extends Printer { precision: precision, separator: separator, sign: sign, + unitBase: binaryUnitBase, + unitOffset: binaryUnitOffset, + unitPrecision: unitPrecision, unitPrefix: unitPrefix, unitSeparator: unitSeparator, - unitBase: binaryUnitBase, units: long ? binaryUnitsLong : binaryUnitsShort, ); @@ -209,34 +226,39 @@ class HumanNumberPrinter extends Printer { /// Whether the unit should be used as a prefix, instead of an suffix. final bool unitPrefix; + /// The number of digits to be printed for unit numbers. + final int unitPrecision; + /// Separator between value and unit. final String unitSeparator; /// The units to be used. final List units; - /// The (internal) printer of the mantissa. - final Printer _mantissa; + /// The printer for integral values. + final Printer _unit; + + /// The printer for scaled values. + final Printer _scaled; @override void printOn(T object, StringBuffer buffer) { final value = object.toDouble(); if (value.isInfinite || value.isNaN) { - _mantissa.printOn(value, buffer); + _unit.printOn(value, buffer); } else { final index = _getExponent(value) + unitOffset; final unitIndex = index.clamp(0, units.length - 1); final unitString = units[unitIndex]; final unitExponent = unitIndex - unitOffset; final mantissa = value / unitBase.toDouble().pow(unitExponent); - if (unitString.isEmpty) { - _mantissa.printOn(mantissa, buffer); - } else if (unitPrefix) { + if (unitString.isNotEmpty && unitPrefix) { buffer.write(unitString); buffer.write(unitSeparator); - _mantissa.printOn(mantissa, buffer); - } else { - _mantissa.printOn(mantissa, buffer); + } + final printer = unitIndex == unitOffset ? _unit : _scaled; + printer.printOn(mantissa, buffer); + if (unitString.isNotEmpty && !unitPrefix) { buffer.write(unitSeparator); buffer.write(unitString); } diff --git a/test/printer_test.dart b/test/printer_test.dart index 341eea66..77fad494 100644 --- a/test/printer_test.dart +++ b/test/printer_test.dart @@ -528,11 +528,34 @@ void main() { final printer = HumanNumberPrinter.decimal(nan: 'n/a'); expect(printer(double.nan), 'n/a'); }); - test('nan', () { + test('infinity', () { final printer = HumanNumberPrinter.decimal(infinity: 'huge'); expect(printer(double.infinity), 'huge'); expect(printer(double.negativeInfinity), '-huge'); }); + test('precision', () { + final printer = HumanNumberPrinter.decimal(precision: 1); + expect(printer(0), '0'); + expect(printer(27), '27'); + expect(printer(999), '999'); + expect(printer(1000), '1.0 k'); + expect(printer(1023), '1.0 k'); + expect(printer(1024), '1.0 k'); + expect(printer(1728), '1.7 k'); + expect(printer(1855425871872), '1.9 T'); + }); + test('unitPrecision', () { + final printer = + HumanNumberPrinter.decimal(precision: 2, unitPrecision: 1); + expect(printer(0), '0.0'); + expect(printer(27), '27.0'); + expect(printer(999), '999.0'); + expect(printer(1000), '1.00 k'); + expect(printer(1023), '1.02 k'); + expect(printer(1024), '1.02 k'); + expect(printer(1728), '1.73 k'); + expect(printer(1855425871872), '1.86 T'); + }); test('unitPrefix', () { final printer = HumanNumberPrinter.decimal(unitPrefix: true); expect(printer(4), '4'); @@ -595,11 +618,34 @@ void main() { final printer = HumanNumberPrinter.binary(nan: 'n/a'); expect(printer(double.nan), 'n/a'); }); - test('nan', () { + test('infinity', () { final printer = HumanNumberPrinter.binary(infinity: 'huge'); expect(printer(double.infinity), 'huge'); expect(printer(double.negativeInfinity), '-huge'); }); + test('precision', () { + final printer = HumanNumberPrinter.binary(precision: 1); + expect(printer(0), '0'); + expect(printer(27), '27'); + expect(printer(999), '999'); + expect(printer(1000), '1000'); + expect(printer(1023), '1023'); + expect(printer(1024), '1.0 Ki'); + expect(printer(1728), '1.7 Ki'); + expect(printer(1855425871872), '1.7 Ti'); + }); + test('unitPrecision', () { + final printer = + HumanNumberPrinter.binary(precision: 2, unitPrecision: 1); + expect(printer(0), '0.0'); + expect(printer(27), '27.0'); + expect(printer(999), '999.0'); + expect(printer(1000), '1000.0'); + expect(printer(1023), '1023.0'); + expect(printer(1024), '1.00 Ki'); + expect(printer(1728), '1.69 Ki'); + expect(printer(1855425871872), '1.69 Ti'); + }); test('unitPrefix', () { final printer = HumanNumberPrinter.binary(unitPrefix: true); expect(printer(4), '4');