mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[SE-0329] Clock/Instant/Duration (#40609)
* [WIP] Initial draft at v2 Clock/Instant/Duration * Ensure the literal types for _DoubleWide are able to be at least 64 bits on 32 bit platforms * static cast timespec members to long * Remove runtime exports from clock functions * Export clock functions in implementations as they are in headers * Clean up internal properties by adding leading underscores, refine availability to a TBD marker macro, and break at 80 lines to match style * Shift operators to concrete Instant types to avoid complexity in solver resolution * Adjust diagnostic note and error expectation of ambiguities to reflect new potential solver (perhaps incorrect) solutions * Update stdlib/public/Concurrency/TaskSleep.swift Co-authored-by: Karoy Lorentey <klorentey@apple.com> * [stdlib][NFC] Remove trailing whitespace * [stdlib] Remove _DoubleWidth from stdlib's ABI * [stdlib] Strip downd _DoubleWidth to _[U]Int128 * Additional adjustments to diagnostic notes and errors expectation of ambiguities to reflect new potential solver (perhaps incorrect) solutions * Disable type checker performance validation for operator overload inferences (rdar://33958047) * Decorate Duration, DurationProtocol, Instant and clocks with @available(SwiftStdlib 9999, *) * Restore diagnostic ambiguity test assertion (due to availability) * Add a rough attempt at implementing time accessors on win32 * Remove unused clock id, rename SPI for swift clock ids and correct a few more missing availabilities * remove obsolete case of realtime clock for dispatch after callout * Use the default implementation of ~ for Int128 and UInt128 * Ensure diagnostic ambiguitiy applies evenly to all platforms and their resolved types * Restore the simd vector build modifications (merge damage) * Update to latest naming results for Instant.Duration * Updates to latest proposal initializers and accessors and adjust encoding/decoding to string based serialization * Update availability for Clock/Instant/Duration methods and types to be 5.7 * Correct *Clock.now to report via the correct runtime API * Ensure the hashing of Duration is based upon the attoseconds hashing * Avoid string based encoding and resort back to high and low bit encoding/decoding but as unkeyed * Adjust naming of component initializer to use suffixes on parameters * Duration decoding should use a mutable container for decoding * fix up components initializer and decode access * Add platform base initializers for timespec and tiemval to and from Duration * Add some first draft documentation for standard library types Duration, DurationProtocol and InstantProtocol * Another round of documentation prose and some drive-by availability fixes * InstantProtocol availability should be 5.7 * Correct linux timeval creation to be Int and not Int32 Co-authored-by: Karoy Lorentey <klorentey@apple.com>
This commit is contained in:
@@ -665,6 +665,10 @@ using JobDelay = unsigned long long;
|
||||
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
|
||||
void swift_task_enqueueGlobalWithDelay(JobDelay delay, Job *job);
|
||||
|
||||
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
|
||||
void swift_task_enqueueGlobalWithDeadline(long long sec, long long nsec,
|
||||
long long tsec, long long tnsec, int clock, Job *job);
|
||||
|
||||
/// Enqueue the given job on the main executor.
|
||||
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
|
||||
void swift_task_enqueueMainExecutor(Job *job);
|
||||
@@ -691,6 +695,21 @@ SWIFT_CC(swift) void (*swift_task_enqueueGlobalWithDelay_hook)(
|
||||
unsigned long long delay, Job *job,
|
||||
swift_task_enqueueGlobalWithDelay_original original);
|
||||
|
||||
typedef SWIFT_CC(swift) void (*swift_task_enqueueGlobalWithDeadline_original)(
|
||||
long long sec,
|
||||
long long nsec,
|
||||
long long tsec,
|
||||
long long tnsec,
|
||||
int clock, Job *job);
|
||||
SWIFT_EXPORT_FROM(swift_Concurrency)
|
||||
SWIFT_CC(swift) void (*swift_task_enqueueGlobalWithDeadline_hook)(
|
||||
long long sec,
|
||||
long long nsec,
|
||||
long long tsec,
|
||||
long long tnsec,
|
||||
int clock, Job *job,
|
||||
swift_task_enqueueGlobalWithDeadline_original original);
|
||||
|
||||
/// A hook to take over main executor enqueueing.
|
||||
typedef SWIFT_CC(swift) void (*swift_task_enqueueMainExecutor_original)(
|
||||
Job *job);
|
||||
@@ -825,6 +844,21 @@ void swift_task_donateThreadToGlobalExecutorUntil(bool (*condition)(void*),
|
||||
|
||||
#endif
|
||||
|
||||
enum swift_clock_id : int {
|
||||
swift_clock_id_continuous = 1,
|
||||
swift_clock_id_suspending = 2
|
||||
};
|
||||
|
||||
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
|
||||
void swift_get_time(long long *seconds,
|
||||
long long *nanoseconds,
|
||||
swift_clock_id clock_id);
|
||||
|
||||
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
|
||||
void swift_get_clock_res(long long *seconds,
|
||||
long long *nanoseconds,
|
||||
swift_clock_id clock_id);
|
||||
|
||||
#ifdef __APPLE__
|
||||
/// A magic symbol whose address is the mask to apply to a frame pointer to
|
||||
/// signal that it is an async frame. Do not try to read the actual value of
|
||||
|
||||
@@ -113,6 +113,10 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I
|
||||
AsyncThrowingStream.swift
|
||||
AsyncStream.cpp
|
||||
Deque.swift
|
||||
Clock.cpp
|
||||
Clock.swift
|
||||
ContinuousClock.swift
|
||||
SuspendingClock.swift
|
||||
${swift_concurrency_extra_sources}
|
||||
linker-support/magic-symbols-for-install-name.c
|
||||
|
||||
|
||||
140
stdlib/public/Concurrency/Clock.cpp
Normal file
140
stdlib/public/Concurrency/Clock.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
//===--- Clock.cpp - Time and clock resolution ----------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "swift/Runtime/Concurrency.h"
|
||||
|
||||
#if __has_include(<time.h>)
|
||||
#define HAS_TIME 1
|
||||
#include <time.h>
|
||||
#endif
|
||||
#if defined(_WIN32)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
using namespace swift;
|
||||
|
||||
SWIFT_EXPORT_FROM(swift_Concurrency)
|
||||
SWIFT_CC(swift)
|
||||
void swift_get_time(
|
||||
long long *seconds,
|
||||
long long *nanoseconds,
|
||||
swift_clock_id clock_id) {
|
||||
switch (clock_id) {
|
||||
case swift_clock_id_continuous: {
|
||||
#if defined(__linux__) && HAS_TIME
|
||||
struct timespec continuous;
|
||||
clock_gettime(CLOCK_BOOTTIME, &continuous);
|
||||
*seconds = continuous.tv_sec;
|
||||
*nanoseconds = continuous.tv_nsec;
|
||||
#elif defined(__APPLE__) && HAS_TIME
|
||||
struct timespec continuous;
|
||||
clock_gettime(CLOCK_MONOTONIC, &continuous);
|
||||
*seconds = continuous.tv_sec;
|
||||
*nanoseconds = continuous.tv_nsec;
|
||||
#elif defined(_WIN32)
|
||||
LARGE_INTEGER freq;
|
||||
QueryPerformanceFrequency(&freq);
|
||||
LARGE_INTEGER count;
|
||||
QueryPerformanceCounter(&count);
|
||||
*seconds = count.QuadPart / freq.QuadPart;
|
||||
if (freq.QuadPart < 1000000000) {
|
||||
*nanoseconds =
|
||||
((count.QuadPart % freq.QuadPart) * 1000000000) / freq.QuadPart;
|
||||
} else {
|
||||
*nanoseconds =
|
||||
(count.QuadPart % freq.QuadPart) * (1000000000.0 / freq.QuadPart);
|
||||
}
|
||||
#else
|
||||
#error Missing platform continuous time definition
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case swift_clock_id_suspending: {
|
||||
#if defined(__linux__) && HAS_TIME
|
||||
struct timespec suspending;
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &suspending);
|
||||
*seconds = suspending.tv_sec;
|
||||
*nanoseconds = suspending.tv_nsec;
|
||||
#elif defined(__APPLE__) && HAS_TIME
|
||||
struct timespec suspending;
|
||||
clock_gettime(CLOCK_UPTIME_RAW, &suspending);
|
||||
*seconds = suspending.tv_sec;
|
||||
*nanoseconds = suspending.tv_nsec;
|
||||
#elif defined(_WIN32)
|
||||
LARGE_INTEGER freq;
|
||||
QueryPerformanceFrequency(&freq);
|
||||
LARGE_INTEGER count;
|
||||
QueryPerformanceCounter(&count);
|
||||
*seconds = count.QuadPart / freq.QuadPart;
|
||||
if (freq.QuadPart < 1000000000) {
|
||||
*nanoseconds =
|
||||
((count.QuadPart % freq.QuadPart) * 1000000000) / freq.QuadPart;
|
||||
} else {
|
||||
*nanoseconds =
|
||||
(count.QuadPart % freq.QuadPart) * (1000000000.0 / freq.QuadPart);
|
||||
}
|
||||
#else
|
||||
#error Missing platform suspending time definition
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SWIFT_EXPORT_FROM(swift_Concurrency)
|
||||
SWIFT_CC(swift)
|
||||
void swift_get_clock_res(
|
||||
long long *seconds,
|
||||
long long *nanoseconds,
|
||||
swift_clock_id clock_id) {
|
||||
switch (clock_id) {
|
||||
case swift_clock_id_continuous: {
|
||||
#if defined(__linux__) && HAS_TIME
|
||||
struct timespec continuous;
|
||||
clock_getres(CLOCK_BOOTTIME, &continuous);
|
||||
*seconds = continuous.tv_sec;
|
||||
*nanoseconds = continuous.tv_nsec;
|
||||
#elif defined(__APPLE__) && HAS_TIME
|
||||
struct timespec continuous;
|
||||
clock_getres(CLOCK_MONOTONIC, &continuous);
|
||||
*seconds = continuous.tv_sec;
|
||||
*nanoseconds = continuous.tv_nsec;
|
||||
#elif defined(_WIN32)
|
||||
*seconds = 0;
|
||||
*nanoseconds = 1000;
|
||||
#else
|
||||
#error Missing platform continuous time definition
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case swift_clock_id_suspending: {
|
||||
struct timespec suspending;
|
||||
#if defined(__linux__) && HAS_TIME
|
||||
clock_getres(CLOCK_MONOTONIC_RAW, &suspending);
|
||||
*seconds = suspending.tv_sec;
|
||||
*nanoseconds = suspending.tv_nsec;
|
||||
#elif defined(__APPLE__) && HAS_TIME
|
||||
clock_gettime(CLOCK_UPTIME_RAW, &suspending);
|
||||
*seconds = suspending.tv_sec;
|
||||
*nanoseconds = suspending.tv_nsec;
|
||||
#elif defined(_WIN32)
|
||||
*seconds = 0;
|
||||
*nanoseconds = 1000;
|
||||
#else
|
||||
#error Missing platform suspending time definition
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
98
stdlib/public/Concurrency/Clock.swift
Normal file
98
stdlib/public/Concurrency/Clock.swift
Normal file
@@ -0,0 +1,98 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2021 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
import Swift
|
||||
|
||||
/// A mechanism in which to measure time, and delay work until a given point
|
||||
/// in time.
|
||||
///
|
||||
/// Types that conform to the `Clock` protocol define a concept of "now" which
|
||||
/// is the specific instant in time that property is accessed. Any pair of calls
|
||||
/// to the `now` property may have a minimum duration between them - this
|
||||
/// minimum resolution is exposed by the `minimumResolution` property to inform
|
||||
/// any user of the type the expected granularity of accuracy.
|
||||
///
|
||||
/// One of the primary uses for clocks is to schedule task sleeping. This method
|
||||
/// resumes the calling task after a given deadline has been met or passed with
|
||||
/// a given tolerance value. The tolerance is expected as a leeway around the
|
||||
/// deadline. The clock may reschedule tasks within the tolerance to ensure
|
||||
/// efficient execution of resumptions by reducing potential operating system
|
||||
/// wake-ups. If no tolerance is specified (i.e. nil is passed in) the sleep
|
||||
/// function is expected to schedule with a default tolerance strategy.
|
||||
///
|
||||
/// For more information about specific clocks see `ContinuousClock` and
|
||||
/// `SuspendingClock`.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public protocol Clock: Sendable {
|
||||
associatedtype Instant: InstantProtocol
|
||||
|
||||
var now: Instant { get }
|
||||
var minimumResolution: Instant.Duration { get }
|
||||
|
||||
func sleep(until deadline: Instant, tolerance: Instant.Duration?) async throws
|
||||
}
|
||||
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension Clock {
|
||||
/// Measure the elapsed time to execute a closure.
|
||||
///
|
||||
/// let clock = ContinuousClock()
|
||||
/// let elapsed = clock.measure {
|
||||
/// someWork()
|
||||
/// }
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public func measure(_ work: () throws -> Void) rethrows -> Instant.Duration {
|
||||
let start = now
|
||||
try work()
|
||||
let end = now
|
||||
return start.duration(to: end)
|
||||
}
|
||||
|
||||
/// Measure the elapsed time to execute an asynchronous closure.
|
||||
///
|
||||
/// let clock = ContinuousClock()
|
||||
/// let elapsed = await clock.measure {
|
||||
/// await someWork()
|
||||
/// }
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public func measure(
|
||||
_ work: () async throws -> Void
|
||||
) async rethrows -> Instant.Duration {
|
||||
let start = now
|
||||
try await work()
|
||||
let end = now
|
||||
return start.duration(to: end)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
@usableFromInline
|
||||
enum _ClockID: Int32 {
|
||||
case continuous = 1
|
||||
case suspending = 2
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
@_silgen_name("swift_get_time")
|
||||
@usableFromInline
|
||||
internal func _getTime(
|
||||
seconds: UnsafeMutablePointer<Int64>,
|
||||
nanoseconds: UnsafeMutablePointer<Int64>,
|
||||
clock: _ClockID)
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
@_silgen_name("swift_get_clock_res")
|
||||
@usableFromInline
|
||||
internal func _getClockRes(
|
||||
seconds: UnsafeMutablePointer<Int64>,
|
||||
nanoseconds: UnsafeMutablePointer<Int64>,
|
||||
clock: _ClockID)
|
||||
165
stdlib/public/Concurrency/ContinuousClock.swift
Normal file
165
stdlib/public/Concurrency/ContinuousClock.swift
Normal file
@@ -0,0 +1,165 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2021 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
import Swift
|
||||
|
||||
/// A clock that measures time that always increments but does not stop
|
||||
/// incrementing while the system is asleep.
|
||||
///
|
||||
/// `ContinuousClock` can be considered as a stopwatch style time. The frame of
|
||||
/// reference of the `Instant` may be bound to process launch, machine boot or
|
||||
/// some other locally defined reference point. This means that the instants are
|
||||
/// only comparable locally during the execution of a program.
|
||||
///
|
||||
/// This clock is suitable for high resolution measurements of execution.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public struct ContinuousClock {
|
||||
/// A continuous point in time used for `ContinuousClock`.
|
||||
public struct Instant: Codable, Sendable {
|
||||
internal var _value: Swift.Duration
|
||||
|
||||
internal init(_value: Swift.Duration) {
|
||||
self._value = _value
|
||||
}
|
||||
}
|
||||
|
||||
public init() { }
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension Clock where Self == ContinuousClock {
|
||||
/// A clock that measures time that always increments but does not stop
|
||||
/// incrementing while the system is asleep.
|
||||
///
|
||||
/// try await Task.sleep(until: .now + .seconds(3), clock: .continuous)
|
||||
///
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static var continuous: ContinuousClock { return ContinuousClock() }
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension ContinuousClock: Clock {
|
||||
/// The current continuous instant.
|
||||
public var now: ContinuousClock.Instant {
|
||||
ContinuousClock.now
|
||||
}
|
||||
|
||||
/// The minimum non-zero resolution between any two calls to `now`.
|
||||
public var minimumResolution: Swift.Duration {
|
||||
var seconds = Int64(0)
|
||||
var nanoseconds = Int64(0)
|
||||
_getClockRes(
|
||||
seconds: &seconds,
|
||||
nanoseconds: &nanoseconds,
|
||||
clock: .continuous)
|
||||
return .seconds(seconds) + .nanoseconds(nanoseconds)
|
||||
}
|
||||
|
||||
/// The current continuous instant.
|
||||
public static var now: ContinuousClock.Instant {
|
||||
var seconds = Int64(0)
|
||||
var nanoseconds = Int64(0)
|
||||
_getTime(
|
||||
seconds: &seconds,
|
||||
nanoseconds: &nanoseconds,
|
||||
clock: .continuous)
|
||||
return ContinuousClock.Instant(_value:
|
||||
.seconds(seconds) + .nanoseconds(nanoseconds))
|
||||
}
|
||||
|
||||
/// Suspend task execution until a given deadline within a tolerance.
|
||||
/// If no tolerance is specified then the system may adjust the deadline
|
||||
/// to coalesce CPU wake-ups to more efficiently process the wake-ups in
|
||||
/// a more power efficient manner.
|
||||
///
|
||||
/// If the task is canceled before the time ends, this function throws
|
||||
/// `CancellationError`.
|
||||
///
|
||||
/// This function doesn't block the underlying thread.
|
||||
public func sleep(
|
||||
until deadline: Instant, tolerance: Swift.Duration? = nil
|
||||
) async throws {
|
||||
let (seconds, attoseconds) = deadline._value.components
|
||||
let nanoseconds = attoseconds / 1_000_000_000
|
||||
try await Task._sleep(until:seconds, nanoseconds,
|
||||
tolerance: tolerance,
|
||||
clock: .continuous)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension ContinuousClock.Instant: InstantProtocol {
|
||||
public static var now: ContinuousClock.Instant { ContinuousClock.now }
|
||||
|
||||
public func advanced(by duration: Swift.Duration) -> ContinuousClock.Instant {
|
||||
return ContinuousClock.Instant(_value: _value + duration)
|
||||
}
|
||||
|
||||
public func duration(to other: ContinuousClock.Instant) -> Swift.Duration {
|
||||
other._value - _value
|
||||
}
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(_value)
|
||||
}
|
||||
|
||||
public static func == (
|
||||
_ lhs: ContinuousClock.Instant, _ rhs: ContinuousClock.Instant
|
||||
) -> Bool {
|
||||
return lhs._value == rhs._value
|
||||
}
|
||||
|
||||
public static func < (
|
||||
_ lhs: ContinuousClock.Instant, _ rhs: ContinuousClock.Instant
|
||||
) -> Bool {
|
||||
return lhs._value < rhs._value
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@inlinable
|
||||
public static func + (
|
||||
_ lhs: ContinuousClock.Instant, _ rhs: Swift.Duration
|
||||
) -> ContinuousClock.Instant {
|
||||
lhs.advanced(by: rhs)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@inlinable
|
||||
public static func += (
|
||||
_ lhs: inout ContinuousClock.Instant, _ rhs: Swift.Duration
|
||||
) {
|
||||
lhs = lhs.advanced(by: rhs)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@inlinable
|
||||
public static func - (
|
||||
_ lhs: ContinuousClock.Instant, _ rhs: Swift.Duration
|
||||
) -> ContinuousClock.Instant {
|
||||
lhs.advanced(by: .zero - rhs)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@inlinable
|
||||
public static func -= (
|
||||
_ lhs: inout ContinuousClock.Instant, _ rhs: Swift.Duration
|
||||
) {
|
||||
lhs = lhs.advanced(by: .zero - rhs)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@inlinable
|
||||
public static func - (
|
||||
_ lhs: ContinuousClock.Instant, _ rhs: ContinuousClock.Instant
|
||||
) -> Swift.Duration {
|
||||
rhs.duration(to: lhs)
|
||||
}
|
||||
}
|
||||
@@ -136,6 +136,16 @@ static void swift_task_enqueueGlobalWithDelayImpl(JobDelay delay,
|
||||
*position = newJob;
|
||||
}
|
||||
|
||||
SWIFT_CC(swift)
|
||||
static void swift_task_enqueueGlobalWithDeadlineImpl(long long sec,
|
||||
long long nsec,
|
||||
long long tsec,
|
||||
long long tnsec,
|
||||
int clock, Job *job) {
|
||||
assert(job && "no job provided");
|
||||
// TODO: implementation
|
||||
}
|
||||
|
||||
/// Recognize jobs in the delayed-jobs queue that are ready to execute
|
||||
/// and move them to the primary queue.
|
||||
static void recognizeReadyDelayedJobs() {
|
||||
|
||||
@@ -225,6 +225,81 @@ static void swift_task_enqueueGlobalWithDelayImpl(JobDelay delay,
|
||||
dispatch_after_f(when, queue, dispatchContext, dispatchFunction);
|
||||
}
|
||||
|
||||
// TODO: The following is cribbed from libdispatch, we should replace it with an official API
|
||||
typedef enum {
|
||||
DISPATCH_CLOCK_UPTIME,
|
||||
DISPATCH_CLOCK_MONOTONIC,
|
||||
DISPATCH_CLOCK_WALL,
|
||||
#define DISPATCH_CLOCK_COUNT (DISPATCH_CLOCK_WALL + 1)
|
||||
} dispatch_clock_t;
|
||||
|
||||
#define DISPATCH_UP_OR_MONOTONIC_TIME_MASK (1ULL << 63)
|
||||
#define DISPATCH_WALLTIME_MASK (1ULL << 62)
|
||||
#define DISPATCH_TIME_MAX_VALUE (DISPATCH_WALLTIME_MASK - 1)
|
||||
static inline uint64_t
|
||||
_dispatch_time_nano2mach(uint64_t value) {
|
||||
#if HAS_MACH_TIME
|
||||
struct mach_timebase_info info = calculateTimebase();
|
||||
return (value * info.denom) / info.numer;
|
||||
#else
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline dispatch_time_t
|
||||
_dispatch_clock_and_value_to_time(dispatch_clock_t clock, uint64_t value)
|
||||
{
|
||||
if (value >= DISPATCH_TIME_MAX_VALUE) {
|
||||
return DISPATCH_TIME_FOREVER;
|
||||
}
|
||||
switch (clock) {
|
||||
case DISPATCH_CLOCK_WALL:
|
||||
return -_dispatch_time_nano2mach(value);
|
||||
case DISPATCH_CLOCK_UPTIME:
|
||||
return _dispatch_time_nano2mach(value);
|
||||
case DISPATCH_CLOCK_MONOTONIC:
|
||||
return _dispatch_time_nano2mach(value) | DISPATCH_UP_OR_MONOTONIC_TIME_MASK;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
// END: REPLACEMENT
|
||||
|
||||
SWIFT_CC(swift)
|
||||
static void swift_task_enqueueGlobalWithDeadlineImpl(long long sec,
|
||||
long long nsec,
|
||||
long long tsec,
|
||||
long long tnsec,
|
||||
int clock, Job *job) {
|
||||
assert(job && "no job provided");
|
||||
|
||||
dispatch_function_t dispatchFunction = &__swift_run_job;
|
||||
void *dispatchContext = job;
|
||||
|
||||
JobPriority priority = job->getPriority();
|
||||
|
||||
auto queue = getGlobalQueue(priority);
|
||||
|
||||
job->SchedulerPrivate[Job::DispatchQueueIndex] =
|
||||
DISPATCH_QUEUE_GLOBAL_EXECUTOR;
|
||||
|
||||
dispatch_time_t when;
|
||||
switch (clock) {
|
||||
case swift_clock_id_continuous: {
|
||||
uint64_t q = sec * NSEC_PER_SEC + nsec;
|
||||
when = _dispatch_clock_and_value_to_time(DISPATCH_CLOCK_MONOTONIC, q);
|
||||
break;
|
||||
}
|
||||
case swift_clock_id_suspending: {
|
||||
uint64_t q = sec * NSEC_PER_SEC + nsec;
|
||||
when = _dispatch_clock_and_value_to_time(DISPATCH_CLOCK_UPTIME, q);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: this should pass the leeway/tolerance along when it is not -1 nanoseconds
|
||||
// either a dispatch_source can be created or a better dispatch_after_f can be made for this
|
||||
dispatch_after_f(when, queue, dispatchContext, dispatchFunction);
|
||||
}
|
||||
|
||||
SWIFT_CC(swift)
|
||||
static void swift_task_enqueueMainExecutorImpl(Job *job) {
|
||||
assert(job && "no job provided");
|
||||
|
||||
@@ -70,6 +70,15 @@ void (*swift::swift_task_enqueueGlobalWithDelay_hook)(
|
||||
JobDelay delay, Job *job,
|
||||
swift_task_enqueueGlobalWithDelay_original original) = nullptr;
|
||||
|
||||
SWIFT_CC(swift)
|
||||
void (*swift::swift_task_enqueueGlobalWithDeadline_hook)(
|
||||
long long sec,
|
||||
long long nsec,
|
||||
long long tsec,
|
||||
long long tnsec,
|
||||
int clock, Job *job,
|
||||
swift_task_enqueueGlobalWithDeadline_original original) = nullptr;
|
||||
|
||||
SWIFT_CC(swift)
|
||||
void (*swift::swift_task_enqueueMainExecutor_hook)(
|
||||
Job *job, swift_task_enqueueMainExecutor_original original) = nullptr;
|
||||
@@ -103,6 +112,19 @@ void swift::swift_task_enqueueGlobalWithDelay(JobDelay delay, Job *job) {
|
||||
swift_task_enqueueGlobalWithDelayImpl(delay, job);
|
||||
}
|
||||
|
||||
void swift::swift_task_enqueueGlobalWithDeadline(
|
||||
long long sec,
|
||||
long long nsec,
|
||||
long long tsec,
|
||||
long long tnsec,
|
||||
int clock, Job *job) {
|
||||
if (swift_task_enqueueGlobalWithDeadline_hook)
|
||||
swift_task_enqueueGlobalWithDeadline_hook(
|
||||
sec, nsec, tsec, tnsec, clock, job, swift_task_enqueueGlobalWithDeadlineImpl);
|
||||
else
|
||||
swift_task_enqueueGlobalWithDeadlineImpl(sec, nsec, tsec, tnsec, clock, job);
|
||||
}
|
||||
|
||||
void swift::swift_task_enqueueMainExecutor(Job *job) {
|
||||
concurrency::trace::job_enqueue_main_executor(job);
|
||||
if (swift_task_enqueueMainExecutor_hook)
|
||||
|
||||
@@ -41,6 +41,18 @@ static void swift_task_enqueueGlobalWithDelayImpl(JobDelay delay,
|
||||
"swift_task_enqueueGlobalWithDelay");
|
||||
}
|
||||
|
||||
SWIFT_CC(swift)
|
||||
static void swift_task_enqueueGlobalWithDeadlineImpl(long long sec,
|
||||
long long nsec,
|
||||
long long tsec,
|
||||
long long tnsec,
|
||||
int clock, Job *job) {
|
||||
assert(job && "no job provided");
|
||||
|
||||
swift_reportError(0, "operation unsupported without libdispatch: "
|
||||
"swift_task_enqueueGlobalWithDeadline");
|
||||
}
|
||||
|
||||
/// Enqueues a task on the main executor.
|
||||
SWIFT_CC(swift)
|
||||
static void swift_task_enqueueMainExecutorImpl(Job *job) {
|
||||
|
||||
170
stdlib/public/Concurrency/SuspendingClock.swift
Normal file
170
stdlib/public/Concurrency/SuspendingClock.swift
Normal file
@@ -0,0 +1,170 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2021 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
import Swift
|
||||
|
||||
/// A clock that measures time that always increments but stops incrementing
|
||||
/// while the system is asleep.
|
||||
///
|
||||
/// `SuspendingClock` can be considered as a system awake time clock. The frame
|
||||
/// of reference of the `Instant` may be bound machine boot or some other
|
||||
/// locally defined reference point. This means that the instants are
|
||||
/// only comparable on the same machine in the same booted session.
|
||||
///
|
||||
/// This clock is suitable for high resolution measurements of execution.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public struct SuspendingClock {
|
||||
public struct Instant: Codable, Sendable {
|
||||
internal var _value: Swift.Duration
|
||||
|
||||
internal init(_value: Swift.Duration) {
|
||||
self._value = _value
|
||||
}
|
||||
}
|
||||
|
||||
public init() { }
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension Clock where Self == SuspendingClock {
|
||||
/// A clock that measures time that always increments but stops incrementing
|
||||
/// while the system is asleep.
|
||||
///
|
||||
/// try await Task.sleep(until: .now + .seconds(3), clock: .suspending)
|
||||
///
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static var suspending: SuspendingClock { return SuspendingClock() }
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension SuspendingClock: Clock {
|
||||
/// The current instant accounting for machine suspension.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public var now: SuspendingClock.Instant {
|
||||
SuspendingClock.now
|
||||
}
|
||||
|
||||
/// The current instant accounting for machine suspension.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static var now: SuspendingClock.Instant {
|
||||
var seconds = Int64(0)
|
||||
var nanoseconds = Int64(0)
|
||||
_getTime(
|
||||
seconds: &seconds,
|
||||
nanoseconds: &nanoseconds,
|
||||
clock: .suspending)
|
||||
return SuspendingClock.Instant(_value:
|
||||
.seconds(seconds) + .nanoseconds(nanoseconds))
|
||||
}
|
||||
|
||||
/// The minimum non-zero resolution between any two calls to `now`.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public var minimumResolution: Swift.Duration {
|
||||
var seconds = Int64(0)
|
||||
var nanoseconds = Int64(0)
|
||||
_getClockRes(
|
||||
seconds: &seconds,
|
||||
nanoseconds: &nanoseconds,
|
||||
clock: .suspending)
|
||||
return .seconds(seconds) + .nanoseconds(nanoseconds)
|
||||
}
|
||||
|
||||
/// Suspend task execution until a given deadline within a tolerance.
|
||||
/// If no tolerance is specified then the system may adjust the deadline
|
||||
/// to coalesce CPU wake-ups to more efficiently process the wake-ups in
|
||||
/// a more power efficient manner.
|
||||
///
|
||||
/// If the task is canceled before the time ends, this function throws
|
||||
/// `CancellationError`.
|
||||
///
|
||||
/// This function doesn't block the underlying thread.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public func sleep(
|
||||
until deadline: Instant, tolerance: Swift.Duration? = nil
|
||||
) async throws {
|
||||
let (seconds, attoseconds) = deadline._value.components
|
||||
let nanoseconds = attoseconds / 1_000_000_000
|
||||
try await Task._sleep(until:seconds, nanoseconds,
|
||||
tolerance: tolerance,
|
||||
clock: .suspending)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension SuspendingClock.Instant: InstantProtocol {
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static var now: SuspendingClock.Instant { SuspendingClock().now }
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public func advanced(by duration: Swift.Duration) -> SuspendingClock.Instant {
|
||||
SuspendingClock.Instant(_value: _value + duration)
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public func duration(to other: SuspendingClock.Instant) -> Swift.Duration {
|
||||
other._value - _value
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(_value)
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func == (
|
||||
_ lhs: SuspendingClock.Instant, _ rhs: SuspendingClock.Instant
|
||||
) -> Bool {
|
||||
return lhs._value == rhs._value
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func < (
|
||||
_ lhs: SuspendingClock.Instant, _ rhs: SuspendingClock.Instant
|
||||
) -> Bool {
|
||||
return lhs._value < rhs._value
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func + (
|
||||
_ lhs: SuspendingClock.Instant, _ rhs: Swift.Duration
|
||||
) -> SuspendingClock.Instant {
|
||||
lhs.advanced(by: rhs)
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func += (
|
||||
_ lhs: inout SuspendingClock.Instant, _ rhs: Swift.Duration
|
||||
) {
|
||||
lhs = lhs.advanced(by: rhs)
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func - (
|
||||
_ lhs: SuspendingClock.Instant, _ rhs: Swift.Duration
|
||||
) -> SuspendingClock.Instant {
|
||||
lhs.advanced(by: .zero - rhs)
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func -= (
|
||||
_ lhs: inout SuspendingClock.Instant, _ rhs: Swift.Duration
|
||||
) {
|
||||
lhs = lhs.advanced(by: .zero - rhs)
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func - (
|
||||
_ lhs: SuspendingClock.Instant, _ rhs: SuspendingClock.Instant
|
||||
) -> Swift.Duration {
|
||||
rhs.duration(to: lhs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -816,6 +816,13 @@ func _enqueueJobGlobal(_ task: Builtin.Job)
|
||||
@usableFromInline
|
||||
func _enqueueJobGlobalWithDelay(_ delay: UInt64, _ task: Builtin.Job)
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
@_silgen_name("swift_task_enqueueGlobalWithDeadline")
|
||||
@usableFromInline
|
||||
func _enqueueJobGlobalWithDeadline(_ seconds: Int64, _ nanoseconds: Int64,
|
||||
_ toleranceSec: Int64, _ toleranceNSec: Int64,
|
||||
_ clock: Int32, _ task: Builtin.Job)
|
||||
|
||||
@available(SwiftStdlib 5.1, *)
|
||||
@usableFromInline
|
||||
@_silgen_name("swift_task_asyncMainDrainQueue")
|
||||
|
||||
@@ -20,7 +20,8 @@ extension Task where Success == Never, Failure == Never {
|
||||
///
|
||||
/// This function doesn't block the underlying thread.
|
||||
public static func sleep(_ duration: UInt64) async {
|
||||
return await Builtin.withUnsafeContinuation { (continuation: Builtin.RawUnsafeContinuation) -> Void in
|
||||
return await Builtin.withUnsafeContinuation {
|
||||
(continuation: Builtin.RawUnsafeContinuation) -> Void in
|
||||
let job = _taskCreateNullaryContinuationJob(
|
||||
priority: Int(Task.currentPriority.rawValue),
|
||||
continuation: continuation)
|
||||
@@ -293,4 +294,133 @@ extension Task where Success == Never, Failure == Never {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
internal static func _sleep(
|
||||
until seconds: Int64, _ nanoseconds: Int64,
|
||||
tolerance: Duration?,
|
||||
clock: _ClockID
|
||||
) async throws {
|
||||
// Allocate storage for the storage word.
|
||||
let wordPtr = UnsafeMutablePointer<Builtin.Word>.allocate(capacity: 1)
|
||||
|
||||
// Initialize the flag word to "not started", which means the continuation
|
||||
// has neither been created nor completed.
|
||||
Builtin.atomicstore_seqcst_Word(
|
||||
wordPtr._rawValue, SleepState.notStarted.word._builtinWordValue)
|
||||
|
||||
do {
|
||||
// Install a cancellation handler to resume the continuation by
|
||||
// throwing CancellationError.
|
||||
try await withTaskCancellationHandler {
|
||||
let _: () = try await withUnsafeThrowingContinuation { continuation in
|
||||
while true {
|
||||
let state = SleepState(loading: wordPtr)
|
||||
switch state {
|
||||
case .notStarted:
|
||||
// The word that describes the active continuation state.
|
||||
let continuationWord =
|
||||
SleepState.activeContinuation(continuation).word
|
||||
|
||||
// Try to swap in the continuation word.
|
||||
let (_, won) = Builtin.cmpxchg_seqcst_seqcst_Word(
|
||||
wordPtr._rawValue,
|
||||
state.word._builtinWordValue,
|
||||
continuationWord._builtinWordValue)
|
||||
if !Bool(_builtinBooleanLiteral: won) {
|
||||
// Keep trying!
|
||||
continue
|
||||
}
|
||||
|
||||
// Create a task that resumes the continuation normally if it
|
||||
// finishes first. Enqueue it directly with the delay, so it fires
|
||||
// when we're done sleeping.
|
||||
let sleepTaskFlags = taskCreateFlags(
|
||||
priority: nil, isChildTask: false, copyTaskLocals: false,
|
||||
inheritContext: false, enqueueJob: false,
|
||||
addPendingGroupTaskUnconditionally: false)
|
||||
let (sleepTask, _) = Builtin.createAsyncTask(sleepTaskFlags) {
|
||||
onSleepWake(wordPtr)
|
||||
}
|
||||
let toleranceSeconds: Int64
|
||||
let toleranceNanoseconds: Int64
|
||||
if let components = tolerance?.components {
|
||||
toleranceSeconds = components.seconds
|
||||
toleranceNanoseconds = components.attoseconds / 1_000_000_000
|
||||
} else {
|
||||
toleranceSeconds = 0
|
||||
toleranceNanoseconds = -1
|
||||
}
|
||||
|
||||
_enqueueJobGlobalWithDeadline(
|
||||
seconds, nanoseconds,
|
||||
toleranceSeconds, toleranceNanoseconds,
|
||||
clock.rawValue, Builtin.convertTaskToJob(sleepTask))
|
||||
return
|
||||
|
||||
case .activeContinuation, .finished:
|
||||
fatalError("Impossible to have multiple active continuations")
|
||||
|
||||
case .cancelled:
|
||||
fatalError("Impossible to have cancelled before we began")
|
||||
|
||||
case .cancelledBeforeStarted:
|
||||
// Finish the continuation normally. We'll throw later, after
|
||||
// we clean up.
|
||||
continuation.resume()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
} onCancel: {
|
||||
onSleepCancel(wordPtr)
|
||||
}
|
||||
|
||||
// Determine whether we got cancelled before we even started.
|
||||
let cancelledBeforeStarted: Bool
|
||||
switch SleepState(loading: wordPtr) {
|
||||
case .notStarted, .activeContinuation, .cancelled:
|
||||
fatalError("Invalid state for non-cancelled sleep task")
|
||||
|
||||
case .cancelledBeforeStarted:
|
||||
cancelledBeforeStarted = true
|
||||
|
||||
case .finished:
|
||||
cancelledBeforeStarted = false
|
||||
}
|
||||
|
||||
// We got here without being cancelled, so deallocate the storage for
|
||||
// the flag word and continuation.
|
||||
wordPtr.deallocate()
|
||||
|
||||
// If we got cancelled before we even started, through the cancellation
|
||||
// error now.
|
||||
if cancelledBeforeStarted {
|
||||
throw _Concurrency.CancellationError()
|
||||
}
|
||||
} catch {
|
||||
// The task was cancelled; propagate the error. The "on wake" task is
|
||||
// responsible for deallocating the flag word and continuation, if it's
|
||||
// still running.
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/// Suspends the current task until the given deadline within a tolerance.
|
||||
///
|
||||
/// If the task is canceled before the time ends, this function throws
|
||||
/// `CancellationError`.
|
||||
///
|
||||
/// This function doesn't block the underlying thread.
|
||||
///
|
||||
/// try await Task.sleep(until: .now + .seconds(3), clock: .continuous)
|
||||
///
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func sleep<C: Clock>(
|
||||
until deadine: C.Instant,
|
||||
tolerance: C.Instant.Duration? = nil,
|
||||
clock: C
|
||||
) async throws {
|
||||
try await clock.sleep(until: deadine, tolerance: tolerance)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,6 +422,57 @@ public func sem_open(
|
||||
|
||||
#endif
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// time.h
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(Linux)
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension timespec {
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public init(_ duration: Duration) {
|
||||
let comps = duration.components
|
||||
self.init(tv_sec: Int(comps.seconds),
|
||||
tv_nsec: Int(comps.attoseconds / 1_000_000_000))
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension Duration {
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public init(_ ts: timespec) {
|
||||
self = .seconds(ts.tv_sec) + .nanoseconds(ts.tv_nsec)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension timeval {
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public init(_ duration: Duration) {
|
||||
let comps = duration.components
|
||||
#if os(Linux)
|
||||
// Linux platforms define timeval as Int/Int
|
||||
self.init(tv_sec: Int(comps.seconds),
|
||||
tv_usec: Int(comps.attoseconds / 1_000_000_000_000))
|
||||
#else
|
||||
// Darwin platforms define timeval as Int/Int32
|
||||
self.init(tv_sec: Int(comps.seconds),
|
||||
tv_usec: Int32(comps.attoseconds / 1_000_000_000_000))
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension Duration {
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public init(_ tv: timeval) {
|
||||
self = .seconds(tv.tv_sec) + .microseconds(tv.tv_usec)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Misc.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -215,7 +215,10 @@ set(SWIFTLIB_SOURCES
|
||||
CollectionDifference.swift
|
||||
CollectionOfOne.swift
|
||||
Diffing.swift
|
||||
Duration.swift
|
||||
DurationProtocol.swift
|
||||
FloatingPointRandom.swift
|
||||
Instant.swift
|
||||
Mirror.swift
|
||||
PlaygroundDisplay.swift
|
||||
CommandLine.swift
|
||||
@@ -228,6 +231,7 @@ set(SWIFTLIB_SOURCES
|
||||
|
||||
set(SWIFTLIB_GYB_SOURCES
|
||||
${SWIFTLIB_ESSENTIAL_GYB_SOURCES}
|
||||
Int128.swift.gyb
|
||||
Tuple.swift.gyb
|
||||
)
|
||||
|
||||
|
||||
315
stdlib/public/core/Duration.swift
Normal file
315
stdlib/public/core/Duration.swift
Normal file
@@ -0,0 +1,315 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2021 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// A representation of high precision time.
|
||||
///
|
||||
/// `Duration` represents an elapsed time value with high precision in an
|
||||
/// integral form. It may be used for measurements of varying clock sources. In
|
||||
/// those cases it represents the elapsed time measured by that clock.
|
||||
/// Calculations using `Duration` may span from a negative value to a positive
|
||||
/// value and have a suitable range to at least cover attosecond scale for both
|
||||
/// small elapsed durations like sub-second precision to durations that span
|
||||
/// centuries.
|
||||
///
|
||||
/// Typical construction of `Duration` values should be created via the
|
||||
/// static methods for specific time values.
|
||||
///
|
||||
/// var d: Duration = .seconds(3)
|
||||
/// d += .milliseconds(33)
|
||||
/// print(d) // 3.033 seconds
|
||||
///
|
||||
/// `Duration` itself does not ferry any additional information other than the
|
||||
/// temporal measurement component; specifically leap seconds should be
|
||||
/// represented as an additional accessor since that is specific only to certain
|
||||
/// clock implementations.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
@frozen
|
||||
public struct Duration: Sendable {
|
||||
/// The low 64 bits of a 128-bit signed integer value counting attoseconds.
|
||||
@usableFromInline
|
||||
internal var _low: UInt64
|
||||
|
||||
/// The high 64 bits of a 128-bit signed integer value counting attoseconds.
|
||||
@usableFromInline
|
||||
internal var _high: Int64
|
||||
|
||||
internal init(_attoseconds: _Int128) {
|
||||
self._low = _attoseconds.low
|
||||
self._high = _attoseconds.high
|
||||
}
|
||||
|
||||
/// Construct a `Duration` by adding attoseconds to a seconds value.
|
||||
///
|
||||
/// This is useful for when an external decomposed components of a `Duration`
|
||||
/// has been stored and needs to be reconstituted. Since the values are added
|
||||
/// no precondition is expressed for the attoseconds being limited to 1e18.
|
||||
///
|
||||
/// let d1 = Duration(
|
||||
/// secondsComponent: 3,
|
||||
/// attosecondsComponent: 123000000000000000)
|
||||
/// print(d1) // 3.123 seconds
|
||||
///
|
||||
/// let d2 = Duration(
|
||||
/// secondsComponent: 3,
|
||||
/// attosecondsComponent: -123000000000000000)
|
||||
/// print(d2) // 2.877 seconds
|
||||
///
|
||||
/// let d3 = Duration(
|
||||
/// secondsComponent: -3,
|
||||
/// attosecondsComponent: -123000000000000000)
|
||||
/// print(d3) // -3.123 seconds
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - secondsComponent: The seconds component portion of the `Duration`
|
||||
/// value.
|
||||
/// - attosecondsComponent: The attosecond component portion of the
|
||||
/// `Duration` value.
|
||||
public init(secondsComponent: Int64, attosecondsComponent: Int64) {
|
||||
self = Duration.seconds(secondsComponent) +
|
||||
Duration(_attoseconds: _Int128(attosecondsComponent))
|
||||
}
|
||||
|
||||
internal var _attoseconds: _Int128 {
|
||||
_Int128(high: _high, low: _low)
|
||||
}
|
||||
|
||||
/// The composite components of the `Duration`.
|
||||
///
|
||||
/// This is intended for facilitating conversions to existing time types. The
|
||||
/// attoseconds value will not exceed 1e18 or be lower than -1e18.
|
||||
public var components: (seconds: Int64, attoseconds: Int64) {
|
||||
let seconds = _attoseconds / 1_000_000_000_000_000_000
|
||||
let attoseconds =
|
||||
Int64((_attoseconds - seconds * 1_000_000_000_000_000_000))
|
||||
return (Int64(seconds), attoseconds)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension Duration {
|
||||
/// Construct a `Duration` given a number of seconds represented as a
|
||||
/// `BinaryInteger`.
|
||||
///
|
||||
/// let d: Duration = .seconds(77)
|
||||
///
|
||||
/// - Returns: A `Duration` representing a given number of seconds.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func seconds<T: BinaryInteger>(_ seconds: T) -> Duration {
|
||||
return Duration(_attoseconds: _Int128(seconds) *
|
||||
1_000_000_000_000_000_000)
|
||||
}
|
||||
|
||||
/// Construct a `Duration` given a number of seconds represented as a
|
||||
/// `Double` by converting the value into the closest attosecond scale value.
|
||||
///
|
||||
/// let d: Duration = .seconds(22.93)
|
||||
///
|
||||
/// - Returns: A `Duration` representing a given number of seconds.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func seconds(_ seconds: Double) -> Duration {
|
||||
return Duration(_attoseconds: _Int128(seconds *
|
||||
1_000_000_000_000_000_000))
|
||||
}
|
||||
|
||||
/// Construct a `Duration` given a number of milliseconds represented as a
|
||||
/// `BinaryInteger`.
|
||||
///
|
||||
/// let d: Duration = .milliseconds(645)
|
||||
///
|
||||
/// - Returns: A `Duration` representing a given number of milliseconds.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func milliseconds<T: BinaryInteger>(
|
||||
_ milliseconds: T
|
||||
) -> Duration {
|
||||
return Duration(_attoseconds: _Int128(milliseconds) *
|
||||
1_000_000_000_000_000)
|
||||
}
|
||||
|
||||
/// Construct a `Duration` given a number of seconds milliseconds as a
|
||||
/// `Double` by converting the value into the closest attosecond scale value.
|
||||
///
|
||||
/// let d: Duration = .milliseconds(88.3)
|
||||
///
|
||||
/// - Returns: A `Duration` representing a given number of milliseconds.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func milliseconds(_ milliseconds: Double) -> Duration {
|
||||
return Duration(_attoseconds: _Int128(milliseconds *
|
||||
1_000_000_000_000_000))
|
||||
}
|
||||
|
||||
/// Construct a `Duration` given a number of microseconds represented as a
|
||||
/// `BinaryInteger`.
|
||||
///
|
||||
/// let d: Duration = .microseconds(12)
|
||||
///
|
||||
/// - Returns: A `Duration` representing a given number of microseconds.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func microseconds<T: BinaryInteger>(
|
||||
_ microseconds: T
|
||||
) -> Duration {
|
||||
return Duration(_attoseconds: _Int128(microseconds) *
|
||||
1_000_000_000_000)
|
||||
}
|
||||
|
||||
/// Construct a `Duration` given a number of seconds microseconds as a
|
||||
/// `Double` by converting the value into the closest attosecond scale value.
|
||||
///
|
||||
/// let d: Duration = .microseconds(382.9)
|
||||
///
|
||||
/// - Returns: A `Duration` representing a given number of microseconds.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func microseconds(_ microseconds: Double) -> Duration {
|
||||
return Duration(_attoseconds: _Int128(microseconds *
|
||||
1_000_000_000_000))
|
||||
}
|
||||
|
||||
/// Construct a `Duration` given a number of nanoseconds represented as a
|
||||
/// `BinaryInteger`.
|
||||
///
|
||||
/// let d: Duration = .nanoseconds(1929)
|
||||
///
|
||||
/// - Returns: A `Duration` representing a given number of nanoseconds.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func nanoseconds<T: BinaryInteger>(
|
||||
_ nanoseconds: T
|
||||
) -> Duration {
|
||||
return Duration(_attoseconds: _Int128(nanoseconds) *
|
||||
1_000_000_000)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension Duration: Codable {
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public init(from decoder: Decoder) throws {
|
||||
var container = try decoder.unkeyedContainer()
|
||||
let high = try container.decode(Int64.self)
|
||||
let low = try container.decode(UInt64.self)
|
||||
self.init(_attoseconds: _Int128(high: high, low: low))
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.unkeyedContainer()
|
||||
try container.encode(_high)
|
||||
try container.encode(_low)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension Duration: Hashable {
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(_attoseconds)
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension Duration: Equatable {
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func == (_ lhs: Duration, _ rhs: Duration) -> Bool {
|
||||
return lhs._attoseconds == rhs._attoseconds
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension Duration: Comparable {
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func < (_ lhs: Duration, _ rhs: Duration) -> Bool {
|
||||
return lhs._attoseconds < rhs._attoseconds
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension Duration: AdditiveArithmetic {
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static var zero: Duration { Duration(_attoseconds: 0) }
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func + (_ lhs: Duration, _ rhs: Duration) -> Duration {
|
||||
return Duration(_attoseconds: lhs._attoseconds + rhs._attoseconds)
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func - (_ lhs: Duration, _ rhs: Duration) -> Duration {
|
||||
return Duration(_attoseconds: lhs._attoseconds - rhs._attoseconds)
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func += (_ lhs: inout Duration, _ rhs: Duration) {
|
||||
lhs = lhs + rhs
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func -= (_ lhs: inout Duration, _ rhs: Duration) {
|
||||
lhs = lhs - rhs
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension Duration {
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func / (_ lhs: Duration, _ rhs: Double) -> Duration {
|
||||
return Duration(_attoseconds:
|
||||
_Int128(Double(lhs._attoseconds) / rhs))
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func /= (_ lhs: inout Duration, _ rhs: Double) {
|
||||
lhs = lhs / rhs
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func / <T: BinaryInteger>(
|
||||
_ lhs: Duration, _ rhs: T
|
||||
) -> Duration {
|
||||
Duration(_attoseconds: lhs._attoseconds / _Int128(rhs))
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func /= <T: BinaryInteger>(_ lhs: inout Duration, _ rhs: T) {
|
||||
lhs = lhs / rhs
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func / (_ lhs: Duration, _ rhs: Duration) -> Double {
|
||||
Double(lhs._attoseconds) / Double(rhs._attoseconds)
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func * (_ lhs: Duration, _ rhs: Double) -> Duration {
|
||||
Duration(_attoseconds: _Int128(Double(lhs._attoseconds) * rhs))
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func * <T: BinaryInteger>(
|
||||
_ lhs: Duration, _ rhs: T
|
||||
) -> Duration {
|
||||
Duration(_attoseconds: lhs._attoseconds * _Int128(rhs))
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func *= <T: BinaryInteger>(_ lhs: inout Duration, _ rhs: T) {
|
||||
lhs = lhs * rhs
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension Duration: CustomStringConvertible {
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public var description: String {
|
||||
return (Double(_attoseconds) / 1e18).description + " seconds"
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension Duration: DurationProtocol { }
|
||||
35
stdlib/public/core/DurationProtocol.swift
Normal file
35
stdlib/public/core/DurationProtocol.swift
Normal file
@@ -0,0 +1,35 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2021 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// A type that defines a duration for a given `InstantProtocol` type.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public protocol DurationProtocol: Comparable, AdditiveArithmetic, Sendable {
|
||||
static func / (_ lhs: Self, _ rhs: Int) -> Self
|
||||
static func /= (_ lhs: inout Self, _ rhs: Int)
|
||||
static func * (_ lhs: Self, _ rhs: Int) -> Self
|
||||
static func *= (_ lhs: inout Self, _ rhs: Int)
|
||||
|
||||
static func / (_ lhs: Self, _ rhs: Self) -> Double
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
extension DurationProtocol {
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func /= (_ lhs: inout Self, _ rhs: Int) {
|
||||
lhs = lhs / rhs
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public static func *= (_ lhs: inout Self, _ rhs: Int) {
|
||||
lhs = lhs * rhs
|
||||
}
|
||||
}
|
||||
@@ -233,7 +233,11 @@
|
||||
"Codable.swift",
|
||||
"LegacyABI.swift",
|
||||
"MigrationSupport.swift",
|
||||
"PtrAuth.swift"
|
||||
"PtrAuth.swift",
|
||||
"Int128.swift",
|
||||
"Duration.swift",
|
||||
"DurationProtocol.swift",
|
||||
"Instant.swift"
|
||||
],
|
||||
"Result": [
|
||||
"Result.swift"
|
||||
|
||||
54
stdlib/public/core/Instant.swift
Normal file
54
stdlib/public/core/Instant.swift
Normal file
@@ -0,0 +1,54 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2021 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// A type that defines a specific point in time for a given `Clock`.
|
||||
@available(SwiftStdlib 5.7, *)
|
||||
public protocol InstantProtocol: Comparable, Hashable, Sendable {
|
||||
associatedtype Duration: DurationProtocol
|
||||
func advanced(by duration: Duration) -> Self
|
||||
func duration(to other: Self) -> Duration
|
||||
}
|
||||
|
||||
/*
|
||||
disabled for now - this perturbs operator resolution
|
||||
extension InstantProtocol {
|
||||
@_alwaysEmitIntoClient
|
||||
@inlinable
|
||||
public static func + (_ lhs: Self, _ rhs: Duration) -> Self {
|
||||
lhs.advanced(by: rhs)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@inlinable
|
||||
public static func += (_ lhs: inout Self, _ rhs: Duration) {
|
||||
lhs = lhs.advanced(by: rhs)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@inlinable
|
||||
public static func - (_ lhs: Self, _ rhs: Duration) -> Self {
|
||||
lhs.advanced(by: .zero - rhs)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@inlinable
|
||||
public static func -= (_ lhs: inout Self, _ rhs: Duration) {
|
||||
lhs = lhs.advanced(by: .zero - rhs)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@inlinable
|
||||
public static func - (_ lhs: Self, _ rhs: Self) -> Duration {
|
||||
rhs.duration(to: lhs)
|
||||
}
|
||||
}
|
||||
*/
|
||||
775
stdlib/public/core/Int128.swift.gyb
Normal file
775
stdlib/public/core/Int128.swift.gyb
Normal file
@@ -0,0 +1,775 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2021 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
% for signed in [False, True]:
|
||||
% U = 'U' if signed else ''
|
||||
/// A 128-bit ${'signed' if signed else 'unsigned'} integer type.
|
||||
internal struct _${U}Int128 {
|
||||
internal typealias High = ${U}Int64
|
||||
internal typealias Low = UInt64
|
||||
|
||||
/// The low part of the value.
|
||||
internal var low: Low
|
||||
|
||||
/// The high part of the value.
|
||||
internal var high: High
|
||||
|
||||
/// Creates a new instance from the given tuple of high and low parts.
|
||||
///
|
||||
/// - Parameter value: The tuple to use as the source of the new instance's
|
||||
/// high and low parts.
|
||||
internal init(_ value: (high: High, low: Low)) {
|
||||
self.low = value.low
|
||||
self.high = value.high
|
||||
}
|
||||
|
||||
internal init(high: High, low: Low) {
|
||||
self.low = low
|
||||
self.high = high
|
||||
}
|
||||
|
||||
internal init() {
|
||||
self.init(high: 0, low: 0)
|
||||
}
|
||||
}
|
||||
|
||||
extension _${U}Int128: CustomStringConvertible {
|
||||
internal var description: String {
|
||||
String(self, radix: 10)
|
||||
}
|
||||
}
|
||||
|
||||
extension _${U}Int128: CustomDebugStringConvertible {
|
||||
internal var debugDescription: String {
|
||||
description
|
||||
}
|
||||
}
|
||||
|
||||
extension _${U}Int128: Equatable {
|
||||
internal static func == (_ lhs: Self, _ rhs: Self) -> Bool {
|
||||
return (lhs.high, lhs.low) == (rhs.high, rhs.low)
|
||||
}
|
||||
}
|
||||
|
||||
extension _${U}Int128: Comparable {
|
||||
internal static func < (_ lhs: Self, _ rhs: Self) -> Bool {
|
||||
(lhs.high, lhs.low) < (rhs.high, rhs.low)
|
||||
}
|
||||
}
|
||||
|
||||
extension _${U}Int128: Hashable {
|
||||
internal func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(low)
|
||||
hasher.combine(high)
|
||||
}
|
||||
}
|
||||
|
||||
extension _${U}Int128 {
|
||||
internal var components: (high: High, low: Low) {
|
||||
@inline(__always) get { (high, low) }
|
||||
@inline(__always) set { (self.high, self.low) = (newValue.high, newValue.low) }
|
||||
}
|
||||
}
|
||||
|
||||
extension _${U}Int128: AdditiveArithmetic {
|
||||
internal static func - (_ lhs: Self, _ rhs: Self) -> Self {
|
||||
var lhs = lhs
|
||||
lhs -= rhs
|
||||
return lhs
|
||||
}
|
||||
|
||||
internal static func -= (_ lhs: inout Self, _ rhs: Self) {
|
||||
let (result, overflow) = lhs.subtractingReportingOverflow(rhs)
|
||||
_precondition(!overflow, "Overflow in -=")
|
||||
lhs = result
|
||||
}
|
||||
|
||||
internal static func + (_ lhs: Self, _ rhs: Self) -> Self {
|
||||
var lhs = lhs
|
||||
lhs += rhs
|
||||
return lhs
|
||||
}
|
||||
|
||||
internal static func += (_ lhs: inout Self, _ rhs: Self) {
|
||||
let (result, overflow) = lhs.addingReportingOverflow(rhs)
|
||||
_precondition(!overflow, "Overflow in +=")
|
||||
lhs = result
|
||||
}
|
||||
}
|
||||
|
||||
extension _${U}Int128: Numeric {
|
||||
internal typealias Magnitude = _UInt128
|
||||
|
||||
internal var magnitude: Magnitude {
|
||||
Magnitude(_wideMagnitude22(self.components))
|
||||
}
|
||||
|
||||
internal init(_ magnitude: Magnitude) {
|
||||
self.init(high: High(magnitude.high), low: magnitude.low)
|
||||
}
|
||||
|
||||
internal init<T: BinaryInteger>(_ source: T) {
|
||||
guard let result = Self(exactly: source) else {
|
||||
preconditionFailure("Value is outside the representable range")
|
||||
}
|
||||
self = result
|
||||
}
|
||||
|
||||
internal init?<T: BinaryInteger>(exactly source: T) {
|
||||
// Can't represent a negative 'source' if Self is unsigned.
|
||||
guard Self.isSigned || source >= 0 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Is 'source' entirely representable in Low?
|
||||
if let low = Low(exactly: source.magnitude) {
|
||||
self.init(source._isNegative ? (~0, ~low &+ 1) : (0, low))
|
||||
} else {
|
||||
// At this point we know source.bitWidth > High.bitWidth, or else we
|
||||
// would've taken the first branch.
|
||||
let lowInT = source & T(~0 as Low)
|
||||
let highInT = source >> Low.bitWidth
|
||||
|
||||
let low = Low(lowInT)
|
||||
guard let high = High(exactly: highInT) else {
|
||||
return nil
|
||||
}
|
||||
self.init(high: high, low: low)
|
||||
}
|
||||
}
|
||||
|
||||
internal static func * (_ lhs: Self, _ rhs: Self) -> Self {
|
||||
var lhs = lhs
|
||||
lhs *= rhs
|
||||
return lhs
|
||||
}
|
||||
|
||||
internal static func *= (_ lhs: inout Self, _ rhs: Self) {
|
||||
let (result, overflow) = lhs.multipliedReportingOverflow(by: rhs)
|
||||
_precondition(!overflow, "Overflow in *=")
|
||||
lhs = result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
% if signed:
|
||||
extension _Int128 {
|
||||
internal typealias Words = _UInt128.Words
|
||||
}
|
||||
% else:
|
||||
extension _UInt128 {
|
||||
internal struct Words {
|
||||
internal var high: High.Words
|
||||
internal var low: Low.Words
|
||||
|
||||
internal init(_ value: _UInt128) {
|
||||
self.init(high: value.high.words, low: value.low.words)
|
||||
}
|
||||
|
||||
internal init(_ value: _Int128) {
|
||||
self.init(_UInt128(truncatingIfNeeded: value))
|
||||
}
|
||||
|
||||
internal init(high: High.Words, low: Low.Words) {
|
||||
self.high = high
|
||||
self.low = low
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension _UInt128.Words: RandomAccessCollection {
|
||||
internal typealias Index = Int
|
||||
|
||||
internal var startIndex: Index {
|
||||
0
|
||||
}
|
||||
|
||||
internal var endIndex: Index {
|
||||
count
|
||||
}
|
||||
|
||||
internal var count: Int {
|
||||
low.count + high.count
|
||||
}
|
||||
|
||||
internal subscript(_ i: Index) -> UInt {
|
||||
if i < low.count {
|
||||
return low[i + low.startIndex]
|
||||
}
|
||||
return high[i - low.count + high.startIndex]
|
||||
}
|
||||
}
|
||||
% end
|
||||
|
||||
extension _${U}Int128: FixedWidthInteger {
|
||||
internal var words: Words {
|
||||
Words(self)
|
||||
}
|
||||
|
||||
internal static var isSigned: Bool {
|
||||
${'true' if signed else 'false'}
|
||||
}
|
||||
|
||||
internal static var max: Self {
|
||||
self.init(high: High.max, low: Low.max)
|
||||
}
|
||||
|
||||
internal static var min: Self {
|
||||
self.init(high: High.min, low: Low.min)
|
||||
}
|
||||
|
||||
internal static var bitWidth: Int {
|
||||
High.bitWidth + Low.bitWidth
|
||||
}
|
||||
|
||||
internal func addingReportingOverflow(
|
||||
_ rhs: Self
|
||||
) -> (partialValue: Self, overflow: Bool) {
|
||||
let (r, o) = _wideAddReportingOverflow22(self.components, rhs.components)
|
||||
return (Self(r), o)
|
||||
}
|
||||
|
||||
internal func subtractingReportingOverflow(
|
||||
_ rhs: Self
|
||||
) -> (partialValue: Self, overflow: Bool) {
|
||||
let (r, o) = _wideSubtractReportingOverflow22(
|
||||
self.components, rhs.components)
|
||||
return (Self(r), o)
|
||||
}
|
||||
|
||||
internal func multipliedReportingOverflow(
|
||||
by rhs: Self
|
||||
) -> (partialValue: Self, overflow: Bool) {
|
||||
let (carry, product) = multipliedFullWidth(by: rhs)
|
||||
let result = Self(truncatingIfNeeded: product)
|
||||
|
||||
let isNegative = Self.isSigned && (self._isNegative != rhs._isNegative)
|
||||
let didCarry = isNegative ? carry != ~Self.zero : carry != Self.zero
|
||||
let hadPositiveOverflow = Self.isSigned &&
|
||||
!isNegative && product.leadingZeroBitCount == 0
|
||||
|
||||
return (result, didCarry || hadPositiveOverflow)
|
||||
}
|
||||
|
||||
internal func quotientAndRemainder(
|
||||
dividingBy other: Self
|
||||
) -> (quotient: Self, remainder: Self) {
|
||||
let (q, r) = _wideDivide22(
|
||||
self.magnitude.components, by: other.magnitude.components)
|
||||
let quotient = Self.Magnitude(q)
|
||||
let remainder = Self.Magnitude(r)
|
||||
guard Self.isSigned else {
|
||||
return (Self(quotient), Self(remainder))
|
||||
}
|
||||
let isNegative = (self.high._isNegative != other.high._isNegative)
|
||||
let quotient_ = (isNegative
|
||||
? quotient == Self.min.magnitude ? Self.min : 0 - Self(quotient)
|
||||
: Self(quotient))
|
||||
let remainder_ = (self.high._isNegative
|
||||
? 0 - Self(remainder)
|
||||
: Self(remainder))
|
||||
return (quotient_, remainder_)
|
||||
}
|
||||
|
||||
internal func dividedReportingOverflow(
|
||||
by other: Self
|
||||
) -> (partialValue: Self, overflow: Bool) {
|
||||
if other == Self.zero {
|
||||
return (self, true)
|
||||
}
|
||||
if Self.isSigned && other == -1 && self == .min {
|
||||
return (self, true)
|
||||
}
|
||||
return (quotientAndRemainder(dividingBy: other).quotient, false)
|
||||
}
|
||||
|
||||
internal func remainderReportingOverflow(
|
||||
dividingBy other: Self
|
||||
) -> (partialValue: Self, overflow: Bool) {
|
||||
if other == Self.zero {
|
||||
return (self, true)
|
||||
}
|
||||
if Self.isSigned && other == -1 && self == .min {
|
||||
return (0, true)
|
||||
}
|
||||
return (quotientAndRemainder(dividingBy: other).remainder, false)
|
||||
}
|
||||
|
||||
internal func multipliedFullWidth(
|
||||
by other: Self
|
||||
) -> (high: Self, low: Magnitude) {
|
||||
let isNegative = Self.isSigned && (self._isNegative != other._isNegative)
|
||||
|
||||
func sum(_ x: Low, _ y: Low, _ z: Low) -> (high: Low, low: Low) {
|
||||
let (sum1, overflow1) = x.addingReportingOverflow(y)
|
||||
let (sum2, overflow2) = sum1.addingReportingOverflow(z)
|
||||
let carry: Low = (overflow1 ? 1 : 0) + (overflow2 ? 1 : 0)
|
||||
return (carry, sum2)
|
||||
}
|
||||
|
||||
let lhs = self.magnitude
|
||||
let rhs = other.magnitude
|
||||
|
||||
let a = rhs.low.multipliedFullWidth(by: lhs.low)
|
||||
let b = rhs.low.multipliedFullWidth(by: lhs.high)
|
||||
let c = rhs.high.multipliedFullWidth(by: lhs.low)
|
||||
let d = rhs.high.multipliedFullWidth(by: lhs.high)
|
||||
|
||||
let mid1 = sum(a.high, b.low, c.low)
|
||||
let mid2 = sum(b.high, c.high, d.low)
|
||||
|
||||
let low = _UInt128(high: mid1.low, low: a.low)
|
||||
let high = _${U}Int128(
|
||||
high: High(mid2.high + d.high),
|
||||
low: mid1.high + mid2.low)
|
||||
|
||||
if isNegative {
|
||||
let (lowComplement, overflow) = (~low).addingReportingOverflow(1)
|
||||
return (~high + (overflow ? 1 : 0), lowComplement)
|
||||
} else {
|
||||
return (high, low)
|
||||
}
|
||||
}
|
||||
|
||||
internal func dividingFullWidth(
|
||||
_ dividend: (high: Self, low: Self.Magnitude)
|
||||
) -> (quotient: Self, remainder: Self) {
|
||||
let m = _wideMagnitude22(dividend)
|
||||
let (q, r) = _wideDivide42(
|
||||
(m.high.components, m.low.components),
|
||||
by: self.magnitude.components)
|
||||
let quotient = Self.Magnitude(q)
|
||||
let remainder = Self.Magnitude(r)
|
||||
guard Self.isSigned else {
|
||||
return (Self(quotient), Self(remainder))
|
||||
}
|
||||
let isNegative = (self.high._isNegative != dividend.high.high._isNegative)
|
||||
let quotient_ = (isNegative
|
||||
? (quotient == Self.min.magnitude ? Self.min : 0 - Self(quotient))
|
||||
: Self(quotient))
|
||||
let remainder_ = (dividend.high.high._isNegative
|
||||
? 0 - Self(remainder)
|
||||
: Self(remainder))
|
||||
return (quotient_, remainder_)
|
||||
}
|
||||
|
||||
/* disabled since it causes a compile failure in LLDB
|
||||
internal static prefix func ~(x: Self) -> Self {
|
||||
Self(high: ~x.high, low: ~x.low)
|
||||
}
|
||||
*/
|
||||
|
||||
internal static func &= (_ lhs: inout Self, _ rhs: Self) {
|
||||
lhs.low &= rhs.low
|
||||
lhs.high &= rhs.high
|
||||
}
|
||||
|
||||
internal static func |= (_ lhs: inout Self, _ rhs: Self) {
|
||||
lhs.low |= rhs.low
|
||||
lhs.high |= rhs.high
|
||||
}
|
||||
|
||||
internal static func ^= (_ lhs: inout Self, _ rhs: Self) {
|
||||
lhs.low ^= rhs.low
|
||||
lhs.high ^= rhs.high
|
||||
}
|
||||
|
||||
internal static func <<= (_ lhs: inout Self, _ rhs: Self) {
|
||||
if Self.isSigned && rhs._isNegative {
|
||||
lhs >>= 0 - rhs
|
||||
return
|
||||
}
|
||||
|
||||
// Shift is larger than this type's bit width.
|
||||
if rhs.high != High.zero || rhs.low >= Self.bitWidth {
|
||||
lhs = 0
|
||||
return
|
||||
}
|
||||
|
||||
lhs &<<= rhs
|
||||
}
|
||||
|
||||
internal static func >>= (_ lhs: inout Self, _ rhs: Self) {
|
||||
if Self.isSigned && rhs._isNegative {
|
||||
lhs <<= 0 - rhs
|
||||
return
|
||||
}
|
||||
|
||||
// Shift is larger than this type's bit width.
|
||||
if rhs.high != High.zero || rhs.low >= Self.bitWidth {
|
||||
lhs = lhs._isNegative ? ~0 : 0
|
||||
return
|
||||
}
|
||||
|
||||
lhs &>>= rhs
|
||||
}
|
||||
|
||||
internal static func &<<= (_ lhs: inout Self, _ rhs: Self) {
|
||||
_wideMaskedShiftLeft(&lhs.components, rhs.low)
|
||||
}
|
||||
|
||||
internal static func &>>= (_ lhs: inout Self, _ rhs: Self) {
|
||||
_wideMaskedShiftRight(&lhs.components, rhs.low)
|
||||
}
|
||||
|
||||
internal static func / (
|
||||
_ lhs: Self, _ rhs: Self
|
||||
) -> Self {
|
||||
var lhs = lhs
|
||||
lhs /= rhs
|
||||
return lhs
|
||||
}
|
||||
|
||||
internal static func /= (_ lhs: inout Self, _ rhs: Self) {
|
||||
let (result, overflow) = lhs.dividedReportingOverflow(by: rhs)
|
||||
_precondition(!overflow, "Overflow in /=")
|
||||
lhs = result
|
||||
}
|
||||
|
||||
internal static func % (
|
||||
_ lhs: Self, _ rhs: Self
|
||||
) -> Self {
|
||||
var lhs = lhs
|
||||
lhs %= rhs
|
||||
return lhs
|
||||
}
|
||||
|
||||
internal static func %= (_ lhs: inout Self, _ rhs: Self) {
|
||||
let (result, overflow) = lhs.remainderReportingOverflow(dividingBy: rhs)
|
||||
_precondition(!overflow, "Overflow in %=")
|
||||
lhs = result
|
||||
}
|
||||
|
||||
internal init(_truncatingBits bits: UInt) {
|
||||
low = Low(_truncatingBits: bits)
|
||||
high = High(_truncatingBits: bits >> UInt(Low.bitWidth))
|
||||
}
|
||||
|
||||
internal init(integerLiteral x: Int64) {
|
||||
self.init(x)
|
||||
}
|
||||
|
||||
internal var leadingZeroBitCount: Int {
|
||||
(high == High.zero
|
||||
? High.bitWidth + low.leadingZeroBitCount
|
||||
: high.leadingZeroBitCount)
|
||||
}
|
||||
|
||||
internal var trailingZeroBitCount: Int {
|
||||
(low == Low.zero
|
||||
? Low.bitWidth + high.trailingZeroBitCount
|
||||
: low.trailingZeroBitCount)
|
||||
}
|
||||
|
||||
internal var nonzeroBitCount: Int {
|
||||
high.nonzeroBitCount + low.nonzeroBitCount
|
||||
}
|
||||
|
||||
internal var byteSwapped: Self {
|
||||
Self(
|
||||
high: High(truncatingIfNeeded: low.byteSwapped),
|
||||
low: Low(truncatingIfNeeded: high.byteSwapped))
|
||||
}
|
||||
}
|
||||
|
||||
extension _${U}Int128: Sendable {}
|
||||
% end
|
||||
|
||||
extension BinaryInteger {
|
||||
@inline(__always)
|
||||
fileprivate var _isNegative: Bool { self < Self.zero }
|
||||
}
|
||||
|
||||
private typealias _Wide2<F: FixedWidthInteger> =
|
||||
(high: F, low: F.Magnitude)
|
||||
|
||||
private typealias _Wide3<F: FixedWidthInteger> =
|
||||
(high: F, mid: F.Magnitude, low: F.Magnitude)
|
||||
|
||||
private typealias _Wide4<F: FixedWidthInteger> =
|
||||
(high: _Wide2<F>, low: (high: F.Magnitude, low: F.Magnitude))
|
||||
|
||||
private func _wideMagnitude22<F: FixedWidthInteger>(
|
||||
_ v: _Wide2<F>
|
||||
) -> _Wide2<F.Magnitude> {
|
||||
var result = (high: F.Magnitude(truncatingIfNeeded: v.high), low: v.low)
|
||||
guard F.isSigned && v.high._isNegative else { return result }
|
||||
result.high = ~result.high
|
||||
result.low = ~result.low
|
||||
return _wideAddReportingOverflow22(result, (high: 0, low: 1)).partialValue
|
||||
}
|
||||
|
||||
private func _wideAddReportingOverflow22<F: FixedWidthInteger>(
|
||||
_ lhs: _Wide2<F>, _ rhs: _Wide2<F>
|
||||
) -> (partialValue: _Wide2<F>, overflow: Bool) {
|
||||
let (low, lowOverflow) = lhs.low.addingReportingOverflow(rhs.low)
|
||||
let (high, highOverflow) = lhs.high.addingReportingOverflow(rhs.high)
|
||||
let overflow = highOverflow || high == F.max && lowOverflow
|
||||
let result = (high: high &+ (lowOverflow ? 1 : 0), low: low)
|
||||
return (partialValue: result, overflow: overflow)
|
||||
}
|
||||
|
||||
private func _wideAdd22<F: FixedWidthInteger>(
|
||||
_ lhs: inout _Wide2<F>, _ rhs: _Wide2<F>
|
||||
) {
|
||||
let (result, overflow) = _wideAddReportingOverflow22(lhs, rhs)
|
||||
_precondition(!overflow, "Overflow in +")
|
||||
lhs = result
|
||||
}
|
||||
|
||||
private func _wideAddReportingOverflow33<F: FixedWidthInteger>(
|
||||
_ lhs: _Wide3<F>, _ rhs: _Wide3<F>
|
||||
) -> (
|
||||
partialValue: _Wide3<F>,
|
||||
overflow: Bool
|
||||
) {
|
||||
let (low, lowOverflow) =
|
||||
_wideAddReportingOverflow22((lhs.mid, lhs.low), (rhs.mid, rhs.low))
|
||||
let (high, highOverflow) = lhs.high.addingReportingOverflow(rhs.high)
|
||||
let result = (high: high &+ (lowOverflow ? 1 : 0), mid: low.high, low: low.low)
|
||||
let overflow = highOverflow || (high == F.max && lowOverflow)
|
||||
return (partialValue: result, overflow: overflow)
|
||||
}
|
||||
|
||||
private func _wideSubtractReportingOverflow22<F: FixedWidthInteger>(
|
||||
_ lhs: _Wide2<F>, _ rhs: _Wide2<F>
|
||||
) -> (partialValue: (high: F, low: F.Magnitude), overflow: Bool) {
|
||||
let (low, lowOverflow) = lhs.low.subtractingReportingOverflow(rhs.low)
|
||||
let (high, highOverflow) = lhs.high.subtractingReportingOverflow(rhs.high)
|
||||
let result = (high: high &- (lowOverflow ? 1 : 0), low: low)
|
||||
let overflow = highOverflow || high == F.min && lowOverflow
|
||||
return (partialValue: result, overflow: overflow)
|
||||
}
|
||||
|
||||
private func _wideSubtract22<F: FixedWidthInteger>(
|
||||
_ lhs: inout _Wide2<F>, _ rhs: _Wide2<F>
|
||||
) {
|
||||
let (result, overflow) = _wideSubtractReportingOverflow22(lhs, rhs)
|
||||
_precondition(!overflow, "Overflow in -")
|
||||
lhs = result
|
||||
}
|
||||
|
||||
private func _wideSubtractReportingOverflow33<F: FixedWidthInteger>(
|
||||
_ lhs: _Wide3<F>, _ rhs: _Wide3<F>
|
||||
) -> (
|
||||
partialValue: _Wide3<F>,
|
||||
overflow: Bool
|
||||
) {
|
||||
let (low, lowOverflow) =
|
||||
_wideSubtractReportingOverflow22((lhs.mid, lhs.low), (rhs.mid, rhs.low))
|
||||
let (high, highOverflow) = lhs.high.subtractingReportingOverflow(rhs.high)
|
||||
let result = (high: high &- (lowOverflow ? 1 : 0), mid: low.high, low: low.low)
|
||||
let overflow = highOverflow || (high == F.min && lowOverflow)
|
||||
return (partialValue: result, overflow: overflow)
|
||||
}
|
||||
|
||||
private func _wideMaskedShiftLeft<F: FixedWidthInteger>(
|
||||
_ lhs: _Wide2<F>, _ rhs: F.Magnitude
|
||||
) -> _Wide2<F> {
|
||||
let bitWidth = F.bitWidth + F.Magnitude.bitWidth
|
||||
_internalInvariant(bitWidth.nonzeroBitCount == 1)
|
||||
|
||||
// Mask rhs by the bit width of the wide value.
|
||||
let rhs = rhs & F.Magnitude(bitWidth &- 1)
|
||||
|
||||
guard rhs < F.Magnitude.bitWidth else {
|
||||
let s = rhs &- F.Magnitude(F.Magnitude.bitWidth)
|
||||
return (high: F(truncatingIfNeeded: lhs.low &<< s), low: 0)
|
||||
}
|
||||
|
||||
guard rhs != F.Magnitude.zero else { return lhs }
|
||||
var high = lhs.high &<< F(rhs)
|
||||
let rollover = F.Magnitude(F.bitWidth) &- rhs
|
||||
high |= F(truncatingIfNeeded: lhs.low &>> rollover)
|
||||
var low = lhs.low &<< rhs
|
||||
return (high, low)
|
||||
}
|
||||
|
||||
private func _wideMaskedShiftLeft<F: FixedWidthInteger>(
|
||||
_ lhs: inout _Wide2<F>, _ rhs: F.Magnitude
|
||||
) {
|
||||
lhs = _wideMaskedShiftLeft(lhs, rhs)
|
||||
}
|
||||
|
||||
private func _wideMaskedShiftRight<F: FixedWidthInteger>(
|
||||
_ lhs: _Wide2<F>, _ rhs: F.Magnitude
|
||||
) -> _Wide2<F> {
|
||||
let bitWidth = F.bitWidth + F.Magnitude.bitWidth
|
||||
_internalInvariant(bitWidth.nonzeroBitCount == 1)
|
||||
|
||||
// Mask rhs by the bit width of the wide value.
|
||||
let rhs = rhs & F.Magnitude(bitWidth &- 1)
|
||||
|
||||
guard rhs < F.bitWidth else {
|
||||
let s = F(rhs &- F.Magnitude(F.bitWidth))
|
||||
return (
|
||||
high: lhs.high._isNegative ? ~0 : 0,
|
||||
low: F.Magnitude(truncatingIfNeeded: lhs.high &>> s))
|
||||
}
|
||||
|
||||
guard rhs != F.zero else { return lhs }
|
||||
var low = lhs.low &>> rhs
|
||||
let rollover = F(F.bitWidth) &- F(rhs)
|
||||
low |= F.Magnitude(truncatingIfNeeded: lhs.high &<< rollover)
|
||||
let high = lhs.high &>> rhs
|
||||
return (high, low)
|
||||
}
|
||||
|
||||
private func _wideMaskedShiftRight<F: FixedWidthInteger>(
|
||||
_ lhs: inout _Wide2<F>, _ rhs: F.Magnitude
|
||||
) {
|
||||
lhs = _wideMaskedShiftRight(lhs, rhs)
|
||||
}
|
||||
|
||||
/// Returns the quotient and remainder after dividing a triple-width magnitude
|
||||
/// `lhs` by a double-width magnitude `rhs`.
|
||||
///
|
||||
/// This operation is conceptually that described by Burnikel and Ziegler
|
||||
/// (1998).
|
||||
private func _wideDivide32<F: FixedWidthInteger & UnsignedInteger>(
|
||||
_ lhs: _Wide3<F>, by rhs: _Wide2<F>
|
||||
) -> (quotient: F, remainder: _Wide2<F>) {
|
||||
// The following invariants are guaranteed to hold by dividingFullWidth or
|
||||
// quotientAndRemainder before this function is invoked:
|
||||
_internalInvariant(lhs.high != F.zero)
|
||||
_internalInvariant(rhs.high.leadingZeroBitCount == 0)
|
||||
_internalInvariant((high: lhs.high, low: lhs.mid) < rhs)
|
||||
|
||||
// Estimate the quotient with a 2/1 division using just the top digits.
|
||||
var quotient = (lhs.high == rhs.high
|
||||
? F.max
|
||||
: rhs.high.dividingFullWidth((high: lhs.high, low: lhs.mid)).quotient)
|
||||
|
||||
// Compute quotient * rhs.
|
||||
// TODO: This could be performed more efficiently.
|
||||
let p1 = quotient.multipliedFullWidth(by: F(rhs.low))
|
||||
let p2 = quotient.multipliedFullWidth(by: rhs.high)
|
||||
let product = _wideAddReportingOverflow33(
|
||||
(high: F.zero, mid: F.Magnitude(p1.high), low: p1.low),
|
||||
(high: p2.high, mid: p2.low, low: .zero)).partialValue
|
||||
|
||||
// Compute the remainder after decrementing quotient as necessary.
|
||||
var remainder = lhs
|
||||
|
||||
while remainder < product {
|
||||
quotient = quotient &- 1
|
||||
remainder = _wideAddReportingOverflow33(
|
||||
remainder,
|
||||
(high: F.zero, mid: F.Magnitude(rhs.high), low: rhs.low)).partialValue
|
||||
}
|
||||
remainder = _wideSubtractReportingOverflow33(remainder, product).partialValue
|
||||
_internalInvariant(remainder.high == 0)
|
||||
return (quotient, (high: F(remainder.mid), low: remainder.low))
|
||||
}
|
||||
|
||||
/// Returns the quotient and remainder after dividing a double-width
|
||||
/// magnitude `lhs` by a double-width magnitude `rhs`.
|
||||
private func _wideDivide22<F: FixedWidthInteger & UnsignedInteger>(
|
||||
_ lhs: _Wide2<F>, by rhs: _Wide2<F>
|
||||
) -> (quotient: _Wide2<F>, remainder: _Wide2<F>) {
|
||||
guard _fastPath(rhs > (F.zero, F.Magnitude.zero)) else {
|
||||
fatalError("Division by zero")
|
||||
}
|
||||
guard rhs < lhs else {
|
||||
if _fastPath(rhs > lhs) { return (quotient: (0, 0), remainder: lhs) }
|
||||
return (quotient: (0, 1), remainder: (0, 0))
|
||||
}
|
||||
|
||||
if lhs.high == F.zero {
|
||||
let (quotient, remainder) =
|
||||
lhs.low.quotientAndRemainder(dividingBy: rhs.low)
|
||||
return ((0, quotient), (0, remainder))
|
||||
}
|
||||
|
||||
if rhs.high == F.zero {
|
||||
let (x, a) = lhs.high.quotientAndRemainder(dividingBy: F(rhs.low))
|
||||
let (y, b) = (a == F.zero
|
||||
? lhs.low.quotientAndRemainder(dividingBy: rhs.low)
|
||||
: rhs.low.dividingFullWidth((F.Magnitude(a), lhs.low)))
|
||||
return (quotient: (high: x, low: y), remainder: (high: 0, low: b))
|
||||
}
|
||||
|
||||
// Left shift both rhs and lhs, then divide and right shift the remainder.
|
||||
let shift = F.Magnitude(rhs.high.leadingZeroBitCount)
|
||||
let rhs = _wideMaskedShiftLeft(rhs, shift)
|
||||
let high = _wideMaskedShiftRight(lhs, F.Magnitude(F.bitWidth) &- shift).low
|
||||
let lhs = _wideMaskedShiftLeft(lhs, shift)
|
||||
let (quotient, remainder) = _wideDivide32(
|
||||
(F(high), F.Magnitude(lhs.high), lhs.low), by: rhs)
|
||||
return (
|
||||
quotient: (high: 0, low: F.Magnitude(quotient)),
|
||||
remainder: _wideMaskedShiftRight(remainder, shift))
|
||||
}
|
||||
|
||||
/// Returns the quotient and remainder after dividing a quadruple-width
|
||||
/// magnitude `lhs` by a double-width magnitude `rhs`.
|
||||
private func _wideDivide42<F: FixedWidthInteger & UnsignedInteger>(
|
||||
_ lhs: _Wide4<F>, by rhs: _Wide2<F>
|
||||
) -> (quotient: _Wide2<F>, remainder: _Wide2<F>) {
|
||||
guard _fastPath(rhs > (F.zero, F.Magnitude.zero)) else {
|
||||
fatalError("Division by zero")
|
||||
}
|
||||
guard _fastPath(rhs >= lhs.high) else {
|
||||
fatalError("Division results in an overflow")
|
||||
}
|
||||
|
||||
if lhs.high == (F.zero, F.Magnitude.zero) {
|
||||
return _wideDivide22((high: F(lhs.low.high), low: lhs.low.low), by: rhs)
|
||||
}
|
||||
|
||||
if rhs.high == F.zero {
|
||||
let a = F.Magnitude(lhs.high.high) % rhs.low
|
||||
let b = (a == F.Magnitude.zero
|
||||
? lhs.high.low % rhs.low
|
||||
: rhs.low.dividingFullWidth((a, lhs.high.low)).remainder)
|
||||
let (x, c) = (b == F.Magnitude.zero
|
||||
? lhs.low.high.quotientAndRemainder(dividingBy: rhs.low)
|
||||
: rhs.low.dividingFullWidth((b, lhs.low.high)))
|
||||
let (y, d) = (c == F.Magnitude.zero
|
||||
? lhs.low.low.quotientAndRemainder(dividingBy: rhs.low)
|
||||
: rhs.low.dividingFullWidth((c, lhs.low.low)))
|
||||
return (quotient: (high: F(x), low: y), remainder: (high: 0, low: d))
|
||||
}
|
||||
|
||||
// Left shift both rhs and lhs, then divide and right shift the remainder.
|
||||
let shift = F.Magnitude(rhs.high.leadingZeroBitCount)
|
||||
let rollover = F.Magnitude(F.bitWidth + F.Magnitude.bitWidth) &- shift
|
||||
let rhs = _wideMaskedShiftLeft(rhs, shift)
|
||||
|
||||
let lh1 = _wideMaskedShiftLeft(lhs.high, shift)
|
||||
let lh2 = _wideMaskedShiftRight(lhs.low, rollover)
|
||||
let lhs = (
|
||||
high: (high: lh1.high | F(lh2.high), low: lh1.low | lh2.low),
|
||||
low: _wideMaskedShiftLeft(lhs.low, shift))
|
||||
|
||||
if
|
||||
lhs.high.high == F.Magnitude.zero,
|
||||
(high: F(lhs.high.low), low: lhs.low.high) < rhs
|
||||
{
|
||||
let (quotient, remainder) = _wideDivide32(
|
||||
(F(lhs.high.low), lhs.low.high, lhs.low.low),
|
||||
by: rhs)
|
||||
return (
|
||||
quotient: (high: 0, low: F.Magnitude(quotient)),
|
||||
remainder: _wideMaskedShiftRight(remainder, shift))
|
||||
}
|
||||
let (x, a) = _wideDivide32(
|
||||
(lhs.high.high, lhs.high.low, lhs.low.high), by: rhs)
|
||||
let (y, b) = _wideDivide32((a.high, a.low, lhs.low.low), by: rhs)
|
||||
return (
|
||||
quotient: (high: x, low: F.Magnitude(y)),
|
||||
remainder: _wideMaskedShiftRight(b, shift))
|
||||
}
|
||||
|
||||
|
||||
extension _UInt128: UnsignedInteger {}
|
||||
extension _Int128: SignedNumeric, SignedInteger {}
|
||||
@@ -71,10 +71,20 @@ class MoviesViewController {
|
||||
|
||||
// SR-15053
|
||||
func SR15053<T : Numeric>(_ a: T, _ b: T) -> T {
|
||||
(a + b) / 2 // expected-error{{cannot convert return expression of type 'Int' to return type 'T'}}
|
||||
// expected-error@-1{{cannot convert value of type 'T' to expected argument type 'Int'}}
|
||||
(a + b) / 2 // expected-note {{overloads for '/' exist with these partially matching parameter lists: (Int, Int)}}
|
||||
// expected-error@-1 {{binary operator '/' cannot be applied to operands of type 'T' and 'Int'}}
|
||||
}
|
||||
|
||||
infix operator %%
|
||||
|
||||
func %% (_ lhs: Int, _ rhs: Int) -> Int {
|
||||
lhs / rhs
|
||||
}
|
||||
|
||||
func %% (_ lhs: Float, _ rhs: Float) -> Float {
|
||||
lhs / rhs
|
||||
}
|
||||
|
||||
func SR15053<T : Numeric>(_ a: T, _ b: T) {
|
||||
(a + b) / 2 // expected-error{{cannot convert value of type 'T' to expected argument type 'Int'}}
|
||||
(a + b) %% 2 // expected-error {{cannot convert value of type 'T' to expected argument type 'Int'}}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,15 @@ func test_UnicodeScalarDoesNotImplementArithmetic(_ us: UnicodeScalar, i: Int) {
|
||||
let b1 = us + us // expected-error {{binary operator '+' cannot be applied to two 'UnicodeScalar' (aka 'Unicode.Scalar') operands}}
|
||||
let b2 = us - us // expected-error {{binary operator '-' cannot be applied to two 'UnicodeScalar' (aka 'Unicode.Scalar') operands}}
|
||||
let b3 = us * us // expected-error {{binary operator '*' cannot be applied to two 'UnicodeScalar' (aka 'Unicode.Scalar') operands}}
|
||||
let b4 = us / us // expected-error {{binary operator '/' cannot be applied to two 'UnicodeScalar' (aka 'Unicode.Scalar') operands}}
|
||||
// DurationProtocol is a near miss here
|
||||
let b4 = us / us // expected-error {{referencing operator function '/' on 'DurationProtocol' requires that 'UnicodeScalar' (aka 'Unicode.Scalar') conform to 'DurationProtocol'}}
|
||||
|
||||
let c1 = us + i // expected-error {{cannot convert value of type 'UnicodeScalar' (aka 'Unicode.Scalar') to expected argument type 'Int'}}
|
||||
let c2 = us - i // expected-error {{cannot convert value of type 'UnicodeScalar' (aka 'Unicode.Scalar') to expected argument type 'Int'}}
|
||||
let c3 = us * i // expected-error {{cannot convert value of type 'UnicodeScalar' (aka 'Unicode.Scalar') to expected argument type 'Int'}}
|
||||
let c4 = us / i // expected-error {{cannot convert value of type 'UnicodeScalar' (aka 'Unicode.Scalar') to expected argument type 'Int'}}
|
||||
let c3 = us * i // expected-note {{overloads for '*' exist with these partially matching parameter lists: (Int, Int)}}
|
||||
// expected-error@-1 {{binary operator '*' cannot be applied to operands of type 'UnicodeScalar' (aka 'Unicode.Scalar') and 'Int'}}
|
||||
let c4 = us / i // expected-note {{overloads for '/' exist with these partially matching parameter lists: (Int, Int)}}
|
||||
// expected-error@-1 {{binary operator '/' cannot be applied to operands of type 'UnicodeScalar' (aka 'Unicode.Scalar') and 'Int'}}
|
||||
|
||||
let d1 = i + us // expected-error {{cannot convert value of type 'UnicodeScalar' (aka 'Unicode.Scalar') to expected argument type 'Int'}}
|
||||
let d2 = i - us // expected-error {{cannot convert value of type 'UnicodeScalar' (aka 'Unicode.Scalar') to expected argument type 'Int'}}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
// expected-no-diagnostics
|
||||
|
||||
// REQUIRES: 33958047
|
||||
|
||||
let a: [Double] = []
|
||||
_ = a.map { $0 - 1.0 }
|
||||
.map { $0 * $0 }
|
||||
|
||||
Reference in New Issue
Block a user