Oscar Byström Ericsson c8b6d204c2
Improved big-number formatting (#346)
* Improved integer and floating point `formatted()` methods.

- [IntegerFormatStyle] I removed the trapping conversion to `Int`. IntegerFormatStyle can format big integers since (#262).
- [FloatingPointFormatStyle] I removed the rounding conversion to `Double`. `formatted()` now does whatever `format(_:)` does.
- [Decimal.FormatStyle] N/A (there were no conversions here).

* Reenabled "Decimal Tests" in NumberFormatStyleTests.swift.

- IntegerFormatStyle big integer tests succeed.
- IntegerFormatStyle.Attributed big integer tests fail (output is clamped to `Int64`).

* Fixes IntegerFormatStyle.Attributed.

- Added a numeric string representation case to ICUNumberFormatter.Value.
- IntegerFormatStyle.Attributed now uses the above instead of `Int64(clamping:)`.

* Removed conversions to Decimal in each integer format style (#186).

BinaryInteger's numeric string representation supersedes Decimal in the following cases:

1. IntegerFormatStyle.
2. integerFormatStyle.Attributed.
3. IntegerFormatStyle.Currency.
4. IntegerFormatStyle.Percent.

* Check whether numeric string is zero using Double.

The numeric string format permits redundant zeros (like `+00.00`).

* Removed `isZero` and `doubleValue` from `ICUNumberFormatter.Value`.

Both `isZero` and `doubleValue` were used in `ByteCountFormatStyle`. These values are now taken from `FormatInput` (`Int64`) instead. Removing them from `ICUNumberFormatter.Value` makes it easier to accommodate non-numeric payloads such as strings, which can be used to format arbitrary precision numbers.

* Added `_format(_:doubleValue:)` to `ByteCountFormatStyle`.

Here's an internal method simliar to the `_format(_:)` method removed earlier because  wants its method back! I removed the first method to accommodate `ICUNumberFormatter.Value` cases that cannot implement `doubleValue`. The new method parameterizes the conversion instead, so you can call it whenever conversions to `Double` are possible.
2023-12-22 07:35:34 +08:00

66 lines
2.7 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#if canImport(FoundationEssentials)
import FoundationEssentials
#endif
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
extension BinaryFloatingPoint {
/// Format `self` with `FloatingPointFormatStyle()`.
public func formatted() -> String {
FloatingPointFormatStyle().format(self)
}
/// Format `self` with the given format.
public func formatted<S>(_ format: S) -> S.FormatOutput where Self == S.FormatInput, S : FormatStyle {
format.format(self)
}
/// Format `self` with the given format. `self` is first converted to `S.FormatInput` type, then format with the given format.
public func formatted<S>(_ format: S) -> S.FormatOutput where S : FormatStyle, S.FormatInput : BinaryFloatingPoint {
format.format(S.FormatInput(self))
}
}
// MARK: - BinaryFloatingPoint + Parsing
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
extension BinaryFloatingPoint {
/// Initialize an instance by parsing `value` with the given `strategy`.
public init<S: ParseStrategy>(_ value: S.ParseInput, strategy: S) throws where S.ParseOutput : BinaryFloatingPoint {
let parsed = try strategy.parse(value)
self = Self(parsed)
}
public init<S: ParseStrategy>(_ value: S.ParseInput, strategy: S) throws where S.ParseOutput == Self {
self = try strategy.parse(value)
}
/// Initialize an instance by parsing `value` with a `ParseStrategy` created with the given `format` and the `lenient` argument.
public init(_ value: String, format: FloatingPointFormatStyle<Self>, lenient: Bool = true) throws {
let parsed = try FloatingPointParseStrategy(format: format, lenient: lenient).parse(value)
self = Self(parsed)
}
public init(_ value: String, format: FloatingPointFormatStyle<Self>.Percent, lenient: Bool = true) throws {
let parsed = try FloatingPointParseStrategy(format: format, lenient: lenient).parse(value)
self = Self(parsed)
}
public init(_ value: String, format: FloatingPointFormatStyle<Self>.Currency, lenient: Bool = true) throws {
let parsed = try FloatingPointParseStrategy(format: format, lenient: lenient).parse(value)
self = Self(parsed)
}
}