Files
swift-mirror/stdlib/public/core/Stride.swift
Doug Gregor 1a1f79c0de Introduce safety checkin for ConcurrentValue conformance.
Introduce checking of ConcurrentValue conformances:
- For structs, check that each stored property conforms to ConcurrentValue
- For enums, check that each associated value conforms to ConcurrentValue
- For classes, check that each stored property is immutable and conforms
  to ConcurrentValue

Because all of the stored properties / associated values need to be
visible for this check to work, limit ConcurrentValue conformances to
be in the same source file as the type definition.

This checking can be disabled by conforming to a new marker protocol,
UnsafeConcurrentValue, that refines ConcurrentValue.
UnsafeConcurrentValue otherwise his no specific meaning. This allows
both "I know what I'm doing" for types that manage concurrent access
themselves as well as enabling retroactive conformance, both of which
are fundamentally unsafe but also quite necessary.

The bulk of this change ended up being to the standard library, because
all conformances of standard library types to the ConcurrentValue
protocol needed to be sunk down into the standard library so they
would benefit from the checking above. There were numerous little
mistakes in the initial pass through the stsandard library types that
have now been corrected.
2021-02-04 03:45:09 -08:00

652 lines
21 KiB
Swift

//===--- Stride.swift - Components for stride(...) iteration --------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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 representing continuous, one-dimensional values that can be offset
/// and measured.
///
/// You can use a type that conforms to the `Strideable` protocol with the
/// `stride(from:to:by:)` and `stride(from:through:by:)` functions. For
/// example, you can use `stride(from:to:by:)` to iterate over an
/// interval of floating-point values:
///
/// for radians in stride(from: 0.0, to: .pi * 2, by: .pi / 2) {
/// let degrees = Int(radians * 180 / .pi)
/// print("Degrees: \(degrees), radians: \(radians)")
/// }
/// // Degrees: 0, radians: 0.0
/// // Degrees: 90, radians: 1.5707963267949
/// // Degrees: 180, radians: 3.14159265358979
/// // Degrees: 270, radians: 4.71238898038469
///
/// The last parameter of these functions is of the associated `Stride`
/// type---the type that represents the distance between any two instances of
/// the `Strideable` type.
///
/// Types that have an integer `Stride` can be used as the boundaries of a
/// countable range or as the lower bound of an iterable one-sided range. For
/// example, you can iterate over a range of `Int` and use sequence and
/// collection methods.
///
/// var sum = 0
/// for x in 1...100 {
/// sum += x
/// }
/// // sum == 5050
///
/// let digits = (0..<10).map(String.init)
/// // ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
///
/// Conforming to the Strideable Protocol
/// =====================================
///
/// To add `Strideable` conformance to a custom type, choose a `Stride` type
/// that can represent the distance between two instances and implement the
/// `advanced(by:)` and `distance(to:)` methods. For example, this
/// hypothetical `Date` type stores its value as the number of days before or
/// after January 1, 2000:
///
/// struct Date: Equatable, CustomStringConvertible {
/// var daysAfterY2K: Int
///
/// var description: String {
/// // ...
/// }
/// }
///
/// The `Stride` type for `Date` is `Int`, inferred from the parameter and
/// return types of `advanced(by:)` and `distance(to:)`:
///
/// extension Date: Strideable {
/// func advanced(by n: Int) -> Date {
/// var result = self
/// result.daysAfterY2K += n
/// return result
/// }
///
/// func distance(to other: Date) -> Int {
/// return other.daysAfterY2K - self.daysAfterY2K
/// }
/// }
///
/// The `Date` type can now be used with the `stride(from:to:by:)` and
/// `stride(from:through:by:)` functions and as the bounds of an iterable
/// range.
///
/// let startDate = Date(daysAfterY2K: 0) // January 1, 2000
/// let endDate = Date(daysAfterY2K: 15) // January 16, 2000
///
/// for date in stride(from: startDate, to: endDate, by: 7) {
/// print(date)
/// }
/// // January 1, 2000
/// // January 8, 2000
/// // January 15, 2000
///
/// - Important: The `Strideable` protocol provides default implementations for
/// the equal-to (`==`) and less-than (`<`) operators that depend on the
/// `Stride` type's implementations. If a type conforming to `Strideable` is
/// its own `Stride` type, it must provide concrete implementations of the
/// two operators to avoid infinite recursion.
public protocol Strideable: Comparable {
/// A type that represents the distance between two values.
associatedtype Stride: SignedNumeric, Comparable
/// Returns the distance from this value to the given value, expressed as a
/// stride.
///
/// If this type's `Stride` type conforms to `BinaryInteger`, then for two
/// values `x` and `y`, and a distance `n = x.distance(to: y)`,
/// `x.advanced(by: n) == y`. Using this method with types that have a
/// noninteger `Stride` may result in an approximation.
///
/// - Parameter other: The value to calculate the distance to.
/// - Returns: The distance from this value to `other`.
///
/// - Complexity: O(1)
func distance(to other: Self) -> Stride
/// Returns a value that is offset the specified distance from this value.
///
/// Use the `advanced(by:)` method in generic code to offset a value by a
/// specified distance. If you're working directly with numeric values, use
/// the addition operator (`+`) instead of this method.
///
/// func addOne<T: Strideable>(to x: T) -> T
/// where T.Stride: ExpressibleByIntegerLiteral
/// {
/// return x.advanced(by: 1)
/// }
///
/// let x = addOne(to: 5)
/// // x == 6
/// let y = addOne(to: 3.5)
/// // y = 4.5
///
/// If this type's `Stride` type conforms to `BinaryInteger`, then for a
/// value `x`, a distance `n`, and a value `y = x.advanced(by: n)`,
/// `x.distance(to: y) == n`. Using this method with types that have a
/// noninteger `Stride` may result in an approximation.
///
/// - Parameter n: The distance to advance this value.
/// - Returns: A value that is offset from this value by `n`.
///
/// - Complexity: O(1)
func advanced(by n: Stride) -> Self
/// `_step` is an implementation detail of Strideable; do not use it directly.
static func _step(
after current: (index: Int?, value: Self),
from start: Self, by distance: Self.Stride
) -> (index: Int?, value: Self)
}
extension Strideable {
@inlinable
public static func < (x: Self, y: Self) -> Bool {
return x.distance(to: y) > 0
}
@inlinable
public static func == (x: Self, y: Self) -> Bool {
return x.distance(to: y) == 0
}
}
extension Strideable {
@inlinable // protocol-only
public static func _step(
after current: (index: Int?, value: Self),
from start: Self, by distance: Self.Stride
) -> (index: Int?, value: Self) {
return (nil, current.value.advanced(by: distance))
}
}
extension Strideable where Stride: FloatingPoint {
@inlinable // protocol-only
public static func _step(
after current: (index: Int?, value: Self),
from start: Self, by distance: Self.Stride
) -> (index: Int?, value: Self) {
if let i = current.index {
// When Stride is a floating-point type, we should avoid accumulating
// rounding error from repeated addition.
return (i + 1, start.advanced(by: Stride(i + 1) * distance))
}
return (nil, current.value.advanced(by: distance))
}
}
extension Strideable where Self: FloatingPoint, Self == Stride {
@inlinable // protocol-only
public static func _step(
after current: (index: Int?, value: Self),
from start: Self, by distance: Self.Stride
) -> (index: Int?, value: Self) {
if let i = current.index {
// When both Self and Stride are the same floating-point type, we should
// take advantage of fused multiply-add (where supported) to eliminate
// intermediate rounding error.
return (i + 1, start.addingProduct(Stride(i + 1), distance))
}
return (nil, current.value.advanced(by: distance))
}
}
/// An iterator for a `StrideTo` instance.
@frozen
public struct StrideToIterator<Element: Strideable> {
@usableFromInline
internal let _start: Element
@usableFromInline
internal let _end: Element
@usableFromInline
internal let _stride: Element.Stride
@usableFromInline
internal var _current: (index: Int?, value: Element)
@inlinable
internal init(_start: Element, end: Element, stride: Element.Stride) {
self._start = _start
_end = end
_stride = stride
_current = (0, _start)
}
}
extension StrideToIterator: IteratorProtocol {
/// Advances to the next element and returns it, or `nil` if no next element
/// exists.
///
/// Once `nil` has been returned, all subsequent calls return `nil`.
@inlinable
public mutating func next() -> Element? {
let result = _current.value
if _stride > 0 ? result >= _end : result <= _end {
return nil
}
_current = Element._step(after: _current, from: _start, by: _stride)
return result
}
}
// FIXME: should really be a Collection, as it is multipass
/// A sequence of values formed by striding over a half-open interval.
///
/// Use the `stride(from:to:by:)` function to create `StrideTo` instances.
@frozen
public struct StrideTo<Element: Strideable> {
@usableFromInline
internal let _start: Element
@usableFromInline
internal let _end: Element
@usableFromInline
internal let _stride: Element.Stride
@inlinable
internal init(_start: Element, end: Element, stride: Element.Stride) {
_precondition(stride != 0, "Stride size must not be zero")
// At start, striding away from end is allowed; it just makes for an
// already-empty Sequence.
self._start = _start
self._end = end
self._stride = stride
}
}
extension StrideTo: Sequence {
/// Returns an iterator over the elements of this sequence.
///
/// - Complexity: O(1).
@inlinable
public __consuming func makeIterator() -> StrideToIterator<Element> {
return StrideToIterator(_start: _start, end: _end, stride: _stride)
}
// FIXME(conditional-conformances): this is O(N) instead of O(1), leaving it
// here until a proper Collection conformance is possible
@inlinable
public var underestimatedCount: Int {
var it = self.makeIterator()
var count = 0
while it.next() != nil {
count += 1
}
return count
}
@inlinable
public func _customContainsEquatableElement(
_ element: Element
) -> Bool? {
if element < _start || _end <= element {
return false
}
return nil
}
}
extension StrideTo: CustomReflectable {
public var customMirror: Mirror {
return Mirror(self, children: ["from": _start, "to": _end, "by": _stride])
}
}
// FIXME(conditional-conformances): This does not yet compile (SR-6474).
#if false
extension StrideTo: RandomAccessCollection
where Element.Stride: BinaryInteger {
public typealias Index = Int
public typealias SubSequence = Slice<StrideTo<Element>>
public typealias Indices = Range<Int>
@inlinable
public var startIndex: Index { return 0 }
@inlinable
public var endIndex: Index { return count }
@inlinable
public var count: Int {
let distance = _start.distance(to: _end)
guard distance != 0 && (distance < 0) == (_stride < 0) else { return 0 }
return Int((distance - 1) / _stride) + 1
}
public subscript(position: Index) -> Element {
_failEarlyRangeCheck(position, bounds: startIndex..<endIndex)
return _start.advanced(by: Element.Stride(position) * _stride)
}
public subscript(bounds: Range<Index>) -> Slice<StrideTo<Element>> {
_failEarlyRangeCheck(bounds, bounds: startIndex ..< endIndex)
return Slice(base: self, bounds: bounds)
}
@inlinable
public func index(before i: Index) -> Index {
_failEarlyRangeCheck(i, bounds: startIndex + 1...endIndex)
return i - 1
}
@inlinable
public func index(after i: Index) -> Index {
_failEarlyRangeCheck(i, bounds: startIndex - 1..<endIndex)
return i + 1
}
}
#endif
/// Returns a sequence from a starting value to, but not including, an end
/// value, stepping by the specified amount.
///
/// You can use this function to stride over values of any type that conforms
/// to the `Strideable` protocol, such as integers or floating-point types.
/// Starting with `start`, each successive value of the sequence adds `stride`
/// until the next value would be equal to or beyond `end`.
///
/// for radians in stride(from: 0.0, to: .pi * 2, by: .pi / 2) {
/// let degrees = Int(radians * 180 / .pi)
/// print("Degrees: \(degrees), radians: \(radians)")
/// }
/// // Degrees: 0, radians: 0.0
/// // Degrees: 90, radians: 1.5707963267949
/// // Degrees: 180, radians: 3.14159265358979
/// // Degrees: 270, radians: 4.71238898038469
///
/// You can use `stride(from:to:by:)` to create a sequence that strides upward
/// or downward. Pass a negative value as `stride` to create a sequence from a
/// higher start to a lower end:
///
/// for countdown in stride(from: 3, to: 0, by: -1) {
/// print("\(countdown)...")
/// }
/// // 3...
/// // 2...
/// // 1...
///
/// If you pass a value as `stride` that moves away from `end`, the sequence
/// contains no values.
///
/// for x in stride(from: 0, to: 10, by: -1) {
/// print(x)
/// }
/// // Nothing is printed.
///
/// - Parameters:
/// - start: The starting value to use for the sequence. If the sequence
/// contains any values, the first one is `start`.
/// - end: An end value to limit the sequence. `end` is never an element of
/// the resulting sequence.
/// - stride: The amount to step by with each iteration. A positive `stride`
/// iterates upward; a negative `stride` iterates downward.
/// - Returns: A sequence from `start` toward, but not including, `end`. Each
/// value in the sequence steps by `stride`.
@inlinable
public func stride<T>(
from start: T, to end: T, by stride: T.Stride
) -> StrideTo<T> {
return StrideTo(_start: start, end: end, stride: stride)
}
/// An iterator for a `StrideThrough` instance.
@frozen
public struct StrideThroughIterator<Element: Strideable> {
@usableFromInline
internal let _start: Element
@usableFromInline
internal let _end: Element
@usableFromInline
internal let _stride: Element.Stride
@usableFromInline
internal var _current: (index: Int?, value: Element)
@usableFromInline
internal var _didReturnEnd: Bool = false
@inlinable
internal init(_start: Element, end: Element, stride: Element.Stride) {
self._start = _start
_end = end
_stride = stride
_current = (0, _start)
}
}
extension StrideThroughIterator: IteratorProtocol {
/// Advances to the next element and returns it, or `nil` if no next element
/// exists.
///
/// Once `nil` has been returned, all subsequent calls return `nil`.
@inlinable
public mutating func next() -> Element? {
let result = _current.value
if _stride > 0 ? result >= _end : result <= _end {
// This check is needed because if we just changed the above operators
// to > and <, respectively, we might advance current past the end
// and throw it out of bounds (e.g. above Int.max) unnecessarily.
if result == _end && !_didReturnEnd {
_didReturnEnd = true
return result
}
return nil
}
_current = Element._step(after: _current, from: _start, by: _stride)
return result
}
}
// FIXME: should really be a Collection, as it is multipass
/// A sequence of values formed by striding over a closed interval.
///
/// Use the `stride(from:through:by:)` function to create `StrideThrough`
/// instances.
@frozen
public struct StrideThrough<Element: Strideable> {
@usableFromInline
internal let _start: Element
@usableFromInline
internal let _end: Element
@usableFromInline
internal let _stride: Element.Stride
@inlinable
internal init(_start: Element, end: Element, stride: Element.Stride) {
_precondition(stride != 0, "Stride size must not be zero")
self._start = _start
self._end = end
self._stride = stride
}
}
extension StrideThrough: Sequence {
/// Returns an iterator over the elements of this sequence.
///
/// - Complexity: O(1).
@inlinable
public __consuming func makeIterator() -> StrideThroughIterator<Element> {
return StrideThroughIterator(_start: _start, end: _end, stride: _stride)
}
// FIXME(conditional-conformances): this is O(N) instead of O(1), leaving it
// here until a proper Collection conformance is possible
@inlinable
public var underestimatedCount: Int {
var it = self.makeIterator()
var count = 0
while it.next() != nil {
count += 1
}
return count
}
@inlinable
public func _customContainsEquatableElement(
_ element: Element
) -> Bool? {
if element < _start || _end < element {
return false
}
return nil
}
}
extension StrideThrough: CustomReflectable {
public var customMirror: Mirror {
return Mirror(self,
children: ["from": _start, "through": _end, "by": _stride])
}
}
// FIXME(conditional-conformances): This does not yet compile (SR-6474).
#if false
extension StrideThrough: RandomAccessCollection
where Element.Stride: BinaryInteger {
public typealias Index = ClosedRangeIndex<Int>
public typealias SubSequence = Slice<StrideThrough<Element>>
@inlinable
public var startIndex: Index {
let distance = _start.distance(to: _end)
return distance == 0 || (distance < 0) == (_stride < 0)
? ClosedRangeIndex(0)
: ClosedRangeIndex()
}
@inlinable
public var endIndex: Index { return ClosedRangeIndex() }
@inlinable
public var count: Int {
let distance = _start.distance(to: _end)
guard distance != 0 else { return 1 }
guard (distance < 0) == (_stride < 0) else { return 0 }
return Int(distance / _stride) + 1
}
public subscript(position: Index) -> Element {
let offset = Element.Stride(position._dereferenced) * _stride
return _start.advanced(by: offset)
}
public subscript(bounds: Range<Index>) -> Slice<StrideThrough<Element>> {
return Slice(base: self, bounds: bounds)
}
@inlinable
public func index(before i: Index) -> Index {
switch i._value {
case .inRange(let n):
_precondition(n > 0, "Incrementing past start index")
return ClosedRangeIndex(n - 1)
case .pastEnd:
_precondition(_end >= _start, "Incrementing past start index")
return ClosedRangeIndex(count - 1)
}
}
@inlinable
public func index(after i: Index) -> Index {
switch i._value {
case .inRange(let n):
return n == (count - 1)
? ClosedRangeIndex()
: ClosedRangeIndex(n + 1)
case .pastEnd:
_preconditionFailure("Incrementing past end index")
}
}
}
#endif
/// Returns a sequence from a starting value toward, and possibly including, an end
/// value, stepping by the specified amount.
///
/// You can use this function to stride over values of any type that conforms
/// to the `Strideable` protocol, such as integers or floating-point types.
/// Starting with `start`, each successive value of the sequence adds `stride`
/// until the next value would be beyond `end`.
///
/// for radians in stride(from: 0.0, through: .pi * 2, by: .pi / 2) {
/// let degrees = Int(radians * 180 / .pi)
/// print("Degrees: \(degrees), radians: \(radians)")
/// }
/// // Degrees: 0, radians: 0.0
/// // Degrees: 90, radians: 1.5707963267949
/// // Degrees: 180, radians: 3.14159265358979
/// // Degrees: 270, radians: 4.71238898038469
/// // Degrees: 360, radians: 6.28318530717959
///
/// You can use `stride(from:through:by:)` to create a sequence that strides
/// upward or downward. Pass a negative value as `stride` to create a sequence
/// from a higher start to a lower end:
///
/// for countdown in stride(from: 3, through: 1, by: -1) {
/// print("\(countdown)...")
/// }
/// // 3...
/// // 2...
/// // 1...
///
/// The value you pass as `end` is not guaranteed to be included in the
/// sequence. If stepping from `start` by `stride` does not produce `end`,
/// the last value in the sequence will be one step before going beyond `end`.
///
/// for multipleOfThree in stride(from: 3, through: 10, by: 3) {
/// print(multipleOfThree)
/// }
/// // 3
/// // 6
/// // 9
///
/// If you pass a value as `stride` that moves away from `end`, the sequence
/// contains no values.
///
/// for x in stride(from: 0, through: 10, by: -1) {
/// print(x)
/// }
/// // Nothing is printed.
///
/// - Parameters:
/// - start: The starting value to use for the sequence. If the sequence
/// contains any values, the first one is `start`.
/// - end: An end value to limit the sequence. `end` is an element of
/// the resulting sequence if and only if it can be produced from `start`
/// using steps of `stride`.
/// - stride: The amount to step by with each iteration. A positive `stride`
/// iterates upward; a negative `stride` iterates downward.
/// - Returns: A sequence from `start` toward, and possibly including, `end`.
/// Each value in the sequence is separated by `stride`.
@inlinable
public func stride<T>(
from start: T, through end: T, by stride: T.Stride
) -> StrideThrough<T> {
return StrideThrough(_start: start, end: end, stride: stride)
}
extension StrideToIterator: ConcurrentValue
where Element: ConcurrentValue, Element.Stride: ConcurrentValue { }
extension StrideTo: ConcurrentValue
where Element: ConcurrentValue, Element.Stride: ConcurrentValue { }
extension StrideThroughIterator: ConcurrentValue
where Element: ConcurrentValue, Element.Stride: ConcurrentValue { }
extension StrideThrough: ConcurrentValue
where Element: ConcurrentValue, Element.Stride: ConcurrentValue { }