Currently we implement adding units larger than `.day` as follows:
- Convert the date to date components
- Update the value of the added component
- Convert the date components back to date
The time of the day information is reduced to a `DateComponents` with, e.g. `hour == 1`, `minute == 30`, at step 1. Then when we convert the `DateComponents` back to `Date` at step 3, we always use the *first* occurrence of the time if it falls into the DST repeated time frame.
This is different from `Calendar_ICU`'s implementation, which uses the *latter* and rewind back the date by the DST transition interval (e.g. 1 hour for Pacific Time).
These yeild the same result except for when the input time and the output time are *both* during DST transition time frame. Update the implementation to match Calendar_ICU's behavior.
* 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.
* Propose API improvements to Calendar
* Version 2
* Remove concrete Sequence types
* Add 'adding' sequence API
* Add ranges to both API
* Add examples and justification for dayOfYear
* Add many alternatives considered
* Reorder arguments; clarify that addition is scaled, not repeated add
* [Gregorian Calendar] Drive-by fix for quarter handling in `dateComponents(from:)`
The current handling for quarter is wrong for leap years. Fix this by reversing the leap year check.
* [Gregorian Calendar] WIP: Implement `ordinality(of:in:for:)`
The implementation follows that in Calendar_ICU. But instead of mutating the stored ICU calendar, we pass around a `Date` and its `DateComponents` to for keeping track of the calculation state.
Unfinished task: There are a few places where we try to find the next date matching a given date component repeatedly in while loops. We need to add failsafe to prevent infinite loop.
* Address compiler warning
* Fix `start(of:at:)`
Similar to #335, it's necessary to only specify relevant components when converting `Date` to `DateComponents` with `dateComponents(:)`. Address the same issue here.
* Add more tests; some of them are currently failing
* [Gregorian Calendar] Bugs in adding functions
Week handling is currently wrong, so adding .week and .yearForWeekOfYear to dates across year boundaries would be wrong.
Adding is implemented as such:
- calculate all date component values for the given date
- add the given value to the given component
- calculate date from the updated date components
When calculating date from the given date components, the heuristics of handling conflicting components, implemented as `ResolvedDateComponents`, may favor the wrong component. We tried working around this by passing in the component to take priority to `ResolvedDateComponents(preferComponent:dateComponents)` in the current implementation, but that logic was still flawed.
Simplify this by only including relevant components in the calculation rather than deferring to `ResolvedDateComponents` to resolve the components.
* A word-based binary integer encoding approach.
These changes aim to achieve two things. The first is making the binary integer text encoding algorithm non-generic so that models such as DoubleWidth perform well. The second is performing mutating division, making arbitrary precision faster. Copying the binary integer's words to a temporary allocation achieves both. Since the new algorithm takes a collection of words, it can also test big integers without big integer models.
* Undid internal to public numeric string representation typo.
* Some minor cleanup.
* Apply suggestions from code review
Some comments w.r.t. expecting Swift.BinaryInteger semantics plus some formatting.
Co-authored-by: Wade Tregaskis <wadetregaskis@mac.com>
Co-authored-by: Tina Liu <49205802+itingliu@users.noreply.github.com>
* Changed to using subscripts per review.
* Some formatting along the lines of previous review comments.
* Updated temporary allocation steps while solving missing spacer nit.
The withUnsafeTemporaryAllocation(of:capacity:) makes no guarantees about the size of the allocated buffer pointer, even though the current implementation covers exactly the requested number of elements.
* Updated numeric string representation tests.
* Changed to numeric string representation v2.
- I changed the return type from ArraySlice to String.
- I changed the ICU number formatter's parameter from ArraySlice to String.
- I changed the structure, although it's similar to `v1`.
- I added `nextUp` to `log10(2)` because it's not obvious that it rounds up (it does).
* Edited some comments. Renamed a variable. Replaced a `guard` with an `if`.
* v2 cleanup. Slices. Preconditions. No force unwrap.
- Slicing (rebasing) the magnitude per review comments.
- Changed division parameter to buffer from buffer slice.
- Changed assertions to preconditions because the difference in performance is small.
- UnsafeMutableBufferPointer.init(start:count:) takes an optional (no force unwrapping).
---------
Co-authored-by: Wade Tregaskis <wadetregaskis@mac.com>
Co-authored-by: Tina Liu <49205802+itingliu@users.noreply.github.com>
* Fix a bug where use of autoupdatingCurrentLocale with number formatters resulted in not-autoupdating behavior
* Remove tests for Measurement in package
* WIP: Implement `date(byAdding components: DateComponents, to date: Date, wrappingComponents: Bool)`
This largely follows ICU's calendar::add and calendar::roll.
* It takes around a minute to run these compatibility tests as of this moment. I expect it to take even longer as we add more tests to it. Disable them on CI for now. The appropriate tests should assert their expected absolute values respectively.
* Add a convenience initializer to Date.Components and use it in tests
* [GregorianCalendar] Implement TimeZone support for `date(from components: DateComponents)`
To support DST-observing time zone, add a helper function for TimeZone to return the raw offset and DST offset individually so we can fine tune the behavior for the time during the skipped time frame and the repeated time frame.
* remove an accidental import
* Add non-compatibility tests
* Review feedback: Remove mention of "GMT" in the date argument
* Review feedback: Change the returning type of DST offset from Int to TimeInterval to be consistent with the existing dstOffset API
* Implement the required function for _TimeZoneBridged
* Fix a missing import
This is caused by ICU's update: rdar://114361374.
Introduce FIXED_ICU_20187 to indicate the ICU version with the fix and update test expectation behind the flag. The upstream change 1afef30549 is scheduled to go into ICU 74. Darwin ICU picked this up earlier than their annual ICU update. When we update FoundationICU to ICU74 we should remove this flag and enable the desired behavior everywhere.
Resolves rdar://118564689
Update the Windows path for `String.range(of:)` being altered to
`String._range(of:anchored:backwards:)`. This repairs the build of
FoundationEssentials on Windows.
* fix(patch): [sc-3840] Use branch instead of hash to be possible to use from the package-data-model.
* fix(patch): [sc-3840] Refer dependencies using branches to avoid SPM complaining.
* fix(patch): Rename ordo/swift-foundation to ordo/package-swift-foundation
* Bump dependency version.
* fix(patch): Bump dependency version
* Bump dependency version.
* Benchmark for predicates.
* Cosmetic fix.
* Rollback changes in the package.
* Make benchmark as a separate package.
* Change directory structure.
* Some more reasonable benchmark defaults.
* Add conditions with computed properties.
* Cosmetic fix.
* Cosmetic fix.
* Add nested computed property benchmarks
* Update Predicates.swift
Add standard project header
* Address PR feedback
* Add link to failed compilation
* Bump tools to 5.9 for the benchmarks, so we can depend on macOS .v14 for predicates directly
* Match parent project platforms exactly, reverted required if #available check for macOS 14
* Dynamically calculate test number to make it easier to add additional tests (the test number is mostly useful for filtering with --filter when wanting to run a specific test)
* Use zero numbering for test cases
* Simplify naming and remove counters, makes filtering benchmarks easier for manual workflows, e.g. swift package benchmark --filter predicateKeypathPropertyCondition
* Add multivariate predicate test
* Polish multivariate test
* Use same naming for multivariate test as for single.
* Fix naming for variadic tests, decrease run time to 3 seconds as we still get enough samples and stable results
---------
Co-authored-by: Joakim Hassila <jocke@ordo.one>
* WIP Gregorian Calendar in FoundationEssentials
Implement `dateComponents(from date:)`. The implementation largely follows that of ICU in calendar.cpp and gregocal.cpp. Julian day calculation algorithm is referenced [The Explanatory Supplement to the Astronomical Almanac](https://aa.usno.navy.mil/publications/exp_supp).
First, calculate the Julian day number from a given `Date`. Then, convert the Julian day number to Gregorian calendar date fields[^1]. The remaining part is the time within the day.
There are a few things to look out for
- Julian day starts at noon, while `Date` uses midnight as the reference time, so we need to adjust it acccordingly at every conversion. Note that ICU uses Modified Julian Day number throughout their codebase, which starts at midnight, so
- Dates close to Gregorian calendar adoption, which is also referred as "cutover" or "transition" date interchangeably, needs to be handled with care. Date before the adoption date were represented in Julian Calendar and Gregorian Calendar after the adoption date. The common Gregorian Calendar adoption date is Friday, 15 October 1582. It's also customizable in the API.
- The week number of a month and a year depends on `firstWeekday` and `minimumDaysInFirstWeek` values. The week starts at `firstWeekday`. Week one must contain `minimumDaysInFirstWeek` number of days.
[^1]: A nice readable version of the Julain - Gregorian converting algorithm: https://en.wikipedia.org/wiki/Julian_day#Julian_day_number_calculation.
* Disable a test that's not available until we implement the function in `GregorianCalendar`.
* Add a precondition for first weekday setter instead of silently dropping the value
* Gregorian Calendar part 2: Implement `date(from components:)`.
The implementation largely follows that of ICU. The logic follows this pattern generally
- Calculate the Julian day number from a given year, month, day of month number
- Add time field values if they are set
- Adjust for timezone offset
The complexity lies in the following situations
(1) The passed-in date components lacks essential fields to determine the Julian day number
(2) The date components has week-related fields set, but no year, month, day of month fields set
(3) The date components has both week-related fields and month, day of month fields set
(4) The day is near Gregorian calendar transition date
For (1), simply assume the start of the year/month/day if the field is missing. The value would be either 0 or 1, depending on if it's 0 or 1 indexed.
For (2), calculate the julian day of the start of the month. Advance by multiples of the given week number.
For (3), we need to determine which fields take over precedence of others. ICU tracks the order of when the fields are modified; newly modified ones always take precedence over past ones. We have not been using this mechanism at all in existing Calendar_ICU's implementation. Instead we've been setting the fields arbitrarily. Therefore, here we simplify ICU's heuristics by assuming the timestamps of modified fields are all equal.
For (4), recalculate the date using Julian calendar if the found date is before Gregorian transition date.
* Fixed IntegerFormatStyle for values > Int64.max.
If I understand the NumberFormatter implementation in the ICU library, this _should_ handle arbitrary-precision numbers, as long as they have a `description` which returns their POSIX-formatted representation, although that's not in the unit tests because it requires a working arbitrary-precision type, and I assume it's not acceptable to pull in a BigInt package for this purpose, and my efforts to make a quick-and-dirty one for testing purposes led only to tears and threats against Xcode's life.
* Removed the reliance on `BinaryInteger.description` for `IntegerFormatStyle`.
This patch introduces an explicit `numericStringRepresentation` property for `BinaryInteger`, that can be relied on to produce exactly the decimal string expected by the ICU library rather than relying on `BinaryInteger`'s default `description` (which happens to produce the same format today but isn't guaranteed to in future, and can be overridden by 3rd party implementations of `BinaryInteger`).
This uses a non-trivial algorithm, nominally for performance although it has not been benchmarked. The trivial (relatively-speaking) algorithm is to just iteratively divide `self` by 10, which produces one digit of the result per iteration. This is in fact what is done for all values that fit into a natural machine word (`UInt`), as a fast path optimisation. But for `BinaryInteger`s which are larger than a machine word - and especially for those that have unbounded size, such as arbitrary-precision integers, dividing that entire number by 10 may be quite expensive. So a potential optimisation - as used in this patch - is to leverage the fact that every `BinaryInteger` is defined in terms of one or more `UInt`s, by (essentially) processing a whole `UInt` at a time. There's still a divide-by-ten loop involved per UInt, but integer division on a natural machine word is likely much faster than those same divisions on the full arbitrary-precision number.
* Use the `.zero` property of `BinaryInteger` than a literal `0` as it may be faster.
It depends on how the compiler treats the literal - e.g. it might already replace that with a simple reference to the `.zero` constant - but this way removes the possibility of an inefficiency (e.g. actually creating a duplicate instance of the zero constant).
* Renamed the helpers from `test` to `check` to avoid any confusion with standalone test cases.
Technically not an issue when they're nested inside test cases, but still potentially confusing to a human. Plus, this way they can be moved up a level without having to be renamed (if later tests would like to use the same helpers).
* Renamed the decimalDigitsAndMagnitudePerWord helper to `check` as well (from `test`), moved it up a level, and changed its `magnitude` parameter to be `UInt`.
This way it can be used from additional test cases in future.
The parameter type change is helpful for any future tests that want to use this with types that might not be initialisable from the necessary integer literal (e.g. an arbitrary-precision integer which doesn't support ExpressibleByIntegerLiteral from StaticBigInt and is thus limited to Int, yet its word magnitude will still be UInt as required by the BinaryInteger protocol and its word magnitude value will not fit into an Int).
* Switched to using UnsafeMutableBufferPointer.initializeElement(at:to) rather than simple assignment via subscripting, as the latter mysteriously crashes once the buffer gets large enough.
I wasn't able to precisely root-cause the crash, but it does seem like it's something to do with ContiguousArray's assignment operator implementation assuming `self` is valid, which of course it isn't (yet) in this case. I didn't explore how `initializeElement(at:to)` does the (figuratively) same assignment without running afoul of this, just observed that it evidently does.
* Corrected the calculation for the (maximum) number of wordStrings needed.
The previous algorithm worked pretty amazingly well, considering how baseless it was in mathematical correctness (it was inspired by examples found in _many_ arbitrary-precision numerics libraries, suggesting many people before me also cargo-culted the calculation - but at least I *checked* it).
It took me a while to find an example case that would actually break it (using a BigInt library) and I wasn't able to find an example that was less than hundreds of digits. I'm sure there's a much smaller value that would expose the problem with the prior code, I just didn't feel it a valuable exercise to go full maths nerd in order to find it.
* Handle negative remainders correctly, by ignore the sign bit.
* Moved the Word == UInt precondition to a location more directly relevant to that invariant.
* Added unit tests for numericStringRepresentation and decimalDigitsAndMagnitudePerWord on a real BigInt implementation.
* Optimised the implementation to use just one buffer to build the output.
This doesn't make the code shorter per-se but it does make it a bit simpler in most respects. It does make the buffer indexing slightly more complicated.
But the benefit, of course, is that it no longer allocates twice as much memory as actually needed, and does less work at runtime to assemble the result.
Because the algorithm emits the resulting digits in reverse order (least significant to most), the buffers get filled from end to front. Since the estimate of required buffer size is only an upper bound, not a precise value, that means sometimes there's some space at the front of the buffer that ends up unused. Rather than doing a memmove to shunt the contents of the buffer up to its front - which would be pretty expensive for non-trivially-sized numbers - the `numericStringRepresentation` property now simply returns an `ArraySlice` instead of a `ContiguousArray`. The callers don't care - same interface as far as they're concerned - and they quickly dispose of the `ArraySlice` which in turn disposes off the underlying `ContiguousArray` anyway.
* Corrected the `digits` count returned by maximumDecimalDigitsForUnsigned (it was one too high).
There _was_ actually a reason for this, originally, I vaguely recall… I just don't know now why. What it was (before this patch) returning was actually the _maximum_ number of decimal digits for values of the given type, which is _not_ what it's actually needed for.
* Simplified the specialisation of `numericStringRepresentation` re. extension type - now just "UInt" outright.
Of course this is equivalent to the prior extension point of "BinaryInteger where Self == UInt". I think I just wrote it that way because of the particular frame of reference I had at the time. Thankfully testing shows that the compiler doesn't require that more obtuse way of writing "UInt" in order to correctly detect and use the specialisation.
* Added a fast path to `decimalDigitsAndMagnitudePerWord` that computes the result directly using pretty trivial maths.
This does require doing a power operation, though, so it requires Darwin or equivalent (e.g. Glibc). And since thats now required I removed the previously hard-coded constant for log10(2) in favour of just calling `log10`. Although I'm not sure if the compiler is clever enough to simplify that to the actual value at compile time, to improve runtime performance. 🤔
It is possible to hard-code the guess values for a finite number of bit widths (of which we really only care about 32 & 64), which would avoid the maths and the depending on Darwin etc, but I couldn't find a way to do that which didn't result in the compiler complaining about unreachable code. It only issues warnings in that case, but still, having pointless warnings forever attached to this code is unpalatable.
* Corrected & refined the wording of various comments.
* Removed outdated precondition check, that Words.Element == UInt.
If that isn't true the code won't compile anyway, as there's no definition of the required helper methods on any type other than UInt.
* Added some additional asserts, for rigour.
* Removed unnecessary use of Word.max.bitWidth when Word.bitWidth returns the same thing, but probably more efficiently.
* Replaced UnsafeMutableBufferPoint.Index.advance(by:) with direct arithmetic, per the directions in that function's definition.
…which say to only use `advance(by:)` for Indexes which are not integers. I'm a bit surprised by this advice - it then hard-codes the integer index assumption for types that ever used them, like UnsafeMutableBufferPointer - but it does seem fairly safe in this case as fast manipulation of indices in UnsafeMutableBufferPointers is important, and so likely to remain simple integers.
* Removed an unnecessary temporary variable ('nextWordInsertPoint').
And I only just realised I'd typoed its name anyway - it should have been `nextWordInsertionPoint`. 🙃
* Made the `numericStringRepresentation` unit tests work when UInt is 32-bit… in theory.
I don't have any way to build or execute the tests in 32-bit, so I cannot test this.
* Commented out the import of attaswift/BigInt and put the tests that depend on it behind canImport guards.
@itingliu recommended (https://github.com/apple/swift-foundation/pull/262#issuecomment-1747414018) not adding this as a dependency (by default) as it's a 3rd party library that could change at any time, in a way that erroneously breaks these unit tests.
But it's still handy to have the tests available if someone wants to go out of their way to try them, as they did prove quite useful in finding bugs during the initial implementation.
* Revised the explanatory comment on why `description` cannot be used instead, despite having the same output for many types of BinaryIntegers.
While the prior comment was correct that the output of `description` can change at any time, which is also a problem, it's not the root problem. `description`'s output is fundamentally not a defined format and there's no guarantee (nor requirement) that any particular BinaryInteger-conforming type use any particular format. It doesn't matter the the built-in types happen to use the desired format, this code needs to work for _all_ BinaryIntegers.
* Corrected comment about the UInt specialisation of `numericStringRepresentation`.
Technically it doesn't need to exist now, because the part the generic implementation relies on is actually the `numericStringRepresentation(intoEndOfBuffer:)` method. But the specialisation is still significantly faster, being much simpler, so it's worth keeping even only for that reason.
* Removed errant comma.
No need to write like James T. Kirk.
* Added rudimentary detection of broken quotientAndRemainder(dividingBy:) implementations.
As the included comment explains, it'd be entirely understandable for an implementor to use e.g. T-division instead of F-division, since the documentation for quotientAndRemainder(dividingBy:) doesn't directly specify what is expected (it merely hints, obtusely, that it's F-division because that's the only way to satisfy its requirement that the remainder's sign match the original value's sign). It's easy to catch this with a precondition, and it simplifies the code by removing the need for a second "isPositive" / "isNegative" variable.
In doing that consolidation I also inverted the variable from "positive" to "negative" because arguably using the term "positive" wasn't correct (it included where the value is zero, which technically doesn't have a sign).
* Removed use of `signum()` in favour of just comparing with the value directly.
I originally assumed (mistakenly) that the return value was some trivial integer type, e.g. `Int`. But it's actually `Self`, making it potentially fairly expensive to create the result, depending on how the type in question is implemented (e.g. Int512 with a fixed-size words array underneath). It's impossible to say in general which approach is faster, but it seems like performance will be more predictable by just comparing with the original value (especially since its comparison operator implementations should by rights be pretty optimised anyway given how likely they are to be frequently used).
* Corrected inaccurate wording in the `decimalDigitsAndMagnitudePerWord` documentation.
* Added some comments in `decimalDigitsAndMagnitudePerWord` delineating the fast vs slow paths and explaining why the fast path isn't universally applicable.
* Simplified a variable name, `remainderAsSelf` → `remainder`.
* Updated copyright headers per @glessard's direction (https://github.com/apple/swift-foundation/pull/262#discussion_r1346604109).
* Added explanatory error messages to the asserts.
These help explain the issue clearly and with relevant details (e.g. ancestor values of the assertion expression itself).
* Corrected typo in unit test name.
* Replaced special-casing of zero in `numericStringRepresentation(intoEndOfBuffer:)` with an assert, at @glessard's request (https://github.com/apple/swift-foundation/pull/262#discussion_r1348043669).
* Moved some comments from the formal method & property documentation into the methods themselves.
The comments in question pertain to implementation details, that probably aren't of interest to mere users of these methods & properties.
At @iCharlesHu's request (https://github.com/apple/swift-foundation/pull/262#discussion_r1347862572).
* Removed the commented-out additions of attaswift/BigInt as a dependency, at @iCharlesHu's request (https://github.com/apple/swift-foundation/pull/262#discussion_r1347863730).
* Changed the "fast path should handle the zero case" assert to a precondition, at @iCharlesHu's request (https://github.com/apple/swift-foundation/pull/262#discussion_r1347867409).
It should never trip as long as `UInt(exactly:)` and the implementation of the concrete type's words property aren't buggy. If either is, then it's likely that the result of this method will be wrong anyway. So the benefit of the check is probably just a faster and clearer failure.
But the downside of the precondition check seems quite small - slight increase in code size and a [hopefully very small] runtime cost.
* Made `numericStringRepresentation(intoEndOfBuffer:)` fileprivate (from the default of internal).
It's not used outside the file and is a fairly specific implementation detail of the `numericStringRepresentation` property, so it would be wise to discourage casual use.
* Removed trailing commas that were originally absent, before https://github.com/apple/swift-foundation/pull/262.
Arguably they should already have been there, to avoid exactly this kind of spurious noise when adding or removing dependencies, but, 🤷♂️.
* Added a broken implementation of `actualBitWidth`.
This is attempting to work around `bitWidth` not working properly (IMO) for FixedWidthIntegers (they return the bit width of the _type_, not the _actual value at hand_).
This is non-trivial to implement because signed numbers. 🙁
Specifically, the use of two's complement (for `BinaryInteger`'s underlying storage, in `words`) - the edge cases of -(every power of two) which fits into a signed type one bit smaller than +(every power of two). So we need to detect powers of two - easy, right? No. We only have a `Numeric` value (for the `magnitude`), which is next to useless because it's _such_ a high-level protocol with very little API.
It _might_ be possible to make this work using just the `words`, by basically reinventing all the necessary arithmetic operations on `words`, but it'll be a bit hairy and duplicative of functionality already in the _actual_ `BinaryInteger` we're operating on (but blocked from us by the type system).
I'm checking this in for posterity - in case for some reason this turns out to be the only viable path - but I think all this is unnecessary… what we really want is the number of bits required to represent the _magnitude_, because that's what we're actually going to convert to a numeric string…
* Revert "Replaced special-casing of zero in `numericStringRepresentation(intoEndOfBuffer:)` with an assert, at @glessard's request (https://github.com/apple/swift-foundation/pull/262#discussion_r1348043669)."
We'd both overlooked the fact that it _can_ be called on zero because it's used for the individual words of the BinaryInteger, any of which can actually be zero.
72cd8f038f0691f785d60c75a96bcac4714c560e
* Finally found a solution for determining the minimum bit width of a given `BinaryInteger`.
I resisted just deriving it from `words` at the outset because I thought surely that's naive; surely there's a more elegant if not more efficient way. But there isn't, as far as I can tell. And this actually isn't complicated nor all that expensive anyway, it turns out (at least for `BinaryInteger`s which natively store their values in two's complement form, and thus don't have to specially generate `words` on demand).
An important aspect of this is that what we care about is _not_ the two's complement form, which is what all the built-ins (e.g. `bitWidth`) nominally return, but that size of the _unsigned_ value that is the _magnitude_. That's what we're actually working on; converting to its constituent decimal digits. So the whole off-by-one problems of two's complement representation, with negative powers of two, etc, are all irrelevant really.
* Added tests using the Numberick 3rd party package (if it's available), to cover fixed-width 128-bit and 256-bit integers.
These are conditionalised on the inclusion of Numberick in Package.swift, which is not the default. Like the existing BigInt tests.
This proved useful as it did reveal a bug - one I'd actually discovered previously but apparently the fix got lost during Git patch shuffling or something - in `magnitudeBitWidth`, whereby it was forgetting to check if the current word is actually non-zero before treating it as relevant (meaning not just zero padding). This wasn't caught by the BigInt tests because those BigInt / BigUInt are flexible-width and only use as many words as strictly necessary to contain the value.
* Corrected precondition failure message and comment: T ⇄ F.
I knew what I meant when I wrote it - I got the actual description correct regarding the rounding mode - but I inverted the two letters. T (for truncating, a la `.rounded(.towardZero)`) vs F (for flooring, a la `.rounded(.down)`).
* Added a comment on the two's complement of `remainder` noting that wrap-around is intentional.
The comment might seem excessive, but in reviewing this I had already forgotten that I was using the ~0 + 1 == 0 trick, and I tried to replace '&+' with plain '+', which then crashes (thankfully I'd also had the foresight to make a unit test case which checks this exact situation). So, for future readers who aren't even me, a comment might save them some time (or anguish). 🙂
We wrongly returned the entire pref dictionary instead of the demanded value.
I did not want to spend too much time adding a test since this is dependent on the the autoupdating current locale. I did verify the following test failed before but passed after the fix.
```Obj-C
- (void)test24HourOverride {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setLocale:[NSLocale autoupdatingCurrentLocale]];
[formatter setLocalizedDateFormatFromTemplate:@"Jmm"];
NSString *dateFormat = formatter.dateFormat;
XCTAssertEqualObjects(dateFormat, @"HH:mm");
}
```
The previous logic for escaping the CLDR escape character for literal strings
in the date pattern string (') when building the Date.FormatString was incorrect,
producing invalid date pattern strings, and thus causing the formatting to fail
under certain circumstances.
* rdar://106770688 (Port test/stdlib/NSStringAPI.swift from the Swift repo)
Batch add `String` and `Substring` tests for from stdlib to FCF. These were removed from stldlib in https://github.com/apple/swift/pull/67252/files and https://github.com/apple/swift/pull/67450/. These tests were added to test Foundation's `StringProtocol` extension that called into `NSString` API.
Now that some of the tests were implemented with Swift natively, they should be made available for FoundationPreview, but we'll track that in a separate PR.
* Address review feedback: clean up availability annotations
* Remove the need of swizzling current locale. Instead, add internal functions those localized functions can call into and pass in a locale explicitly for testing.
* Remove the use of current locale in tests
These are internal extensions, and are not used anywhere except in tests. They also make questionable use of the `pow` function in ways that would eventually lead to interesting errors on Linux and Windows. Best to simply excise them.
* Follow up for #278 : make the required function from FoundationEssentials `package` so we can use it from FoundationI18n
* Workaround TAPI error by removing the default arguments
* Add Duration formatting and utility files to FoundationInternationalization.
This commit moves existing files as-is to FoundationInternationalization. We'll address compatibility fixes in the following commits.
* Add partial implementation for Measurement.FormatStyle
`Duration.FormatStyle` uses `Measurement.FormatStyle.UnitWidth` internally. This PR adds a partial implementation for `Measurement.FormatStyle` to maintain source compatibility for `Duration.FormatStyle`.
`Measurement.FormatStyle` is built on top of `struct Measurement<Dimension>`, which isn't available in the package yet. To unblock ourselves, add stubs for relevant types if they're not available for now.
* Addressing compatibility issues post file move
- Add functions to generate ICU skeleton to `ICUMeasurementNumberFormatter`: The function was originally declared as a `static func` in `Measurement.FormatStyle`. Re-work this into `ICUMeasurementNumberFormatter` since this function is only relevant when used with this class.
- Use Glibc for `pow` when Darwin isn't available
* Move test files
* Move test files
* Compatibility fix: typealias Duration.TimeFormatStyle and Duration.UnitsFormatStyle
XCTest explicitly exports Foundation, so referring to `Duration.UnitsFormatStyle` and `Duration.TimeFormatStyle` raises amibiguity errors on Darwin since the compiler doesn't know if they refer to the ones defined in the package or the one in Foundation.
We've been working around this issue by referring common types with prefix of package name (see TestSupport.swift). However we cannot do that for `Duration.UnitsFormatStyle` since this type is declared as `extension Duration`, and there's no way to disambiguate or typealias extensions on stdlib types. Workaround this by declaring `Duration._UnitsFormatStyle` as a typealias of `Duration.FormatStyle`, and use the former in the test. This way, when Darwin is imported, `_UnitsFormatStyle` would refer to the `Duration.UnitsFormatStyle` declared in Foundation, and the one in the package otherwise.