[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:
Philippe Hausler
2022-02-17 09:32:46 -08:00
committed by GitHub
parent e9d2752776
commit e675b310f8
22 changed files with 2128 additions and 8 deletions

View File

@@ -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

View File

@@ -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

View 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;
}
}
}

View 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)

View 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)
}
}

View File

@@ -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() {

View File

@@ -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");

View File

@@ -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)

View File

@@ -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) {

View 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)
}
}

View File

@@ -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")

View File

@@ -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)
}
}

View File

@@ -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.
//===----------------------------------------------------------------------===//

View File

@@ -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
)

View 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 { }

View 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
}
}

View File

@@ -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"

View 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)
}
}
*/

View 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 {}

View File

@@ -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'}}
}

View File

@@ -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'}}

View File

@@ -5,6 +5,8 @@
// expected-no-diagnostics
// REQUIRES: 33958047
let a: [Double] = []
_ = a.map { $0 - 1.0 }
.map { $0 * $0 }