Files
swift-mirror/stdlib/public/core/CollectionOfOne.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

176 lines
5.5 KiB
Swift

//===--- CollectionOfOne.swift - A Collection with one element ------------===//
//
// 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 collection containing a single element.
///
/// You can use a `CollectionOfOne` instance when you need to efficiently
/// represent a single value as a collection. For example, you can add a
/// single element to an array by using a `CollectionOfOne` instance with the
/// concatenation operator (`+`):
///
/// let a = [1, 2, 3, 4]
/// let toAdd = 100
/// let b = a + CollectionOfOne(toAdd)
/// // b == [1, 2, 3, 4, 100]
@frozen // trivial-implementation
public struct CollectionOfOne<Element> {
@usableFromInline // trivial-implementation
internal var _element: Element
/// Creates an instance containing just the given element.
///
/// - Parameter element: The element to store in the collection.
@inlinable // trivial-implementation
public init(_ element: Element) {
self._element = element
}
}
extension CollectionOfOne {
/// An iterator that produces one or zero instances of an element.
///
/// `IteratorOverOne` is the iterator for the `CollectionOfOne` type.
@frozen // trivial-implementation
public struct Iterator {
@usableFromInline // trivial-implementation
internal var _elements: Element?
/// Construct an instance that generates `_element!`, or an empty
/// sequence if `_element == nil`.
@inlinable // trivial-implementation
public // @testable
init(_elements: Element?) {
self._elements = _elements
}
}
}
extension CollectionOfOne.Iterator: 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`.
///
/// - Returns: The next element in the underlying sequence, if a next element
/// exists; otherwise, `nil`.
@inlinable // trivial-implementation
public mutating func next() -> Element? {
let result = _elements
_elements = nil
return result
}
}
extension CollectionOfOne: RandomAccessCollection, MutableCollection {
public typealias Index = Int
public typealias Indices = Range<Int>
public typealias SubSequence = Slice<CollectionOfOne<Element>>
/// The position of the first element.
///
/// In a `CollectionOfOne` instance, `startIndex` is always `0`.
@inlinable // trivial-implementation
public var startIndex: Index {
return 0
}
/// The "past the end" position---that is, the position one greater than the
/// last valid subscript argument.
///
/// In a `CollectionOfOne` instance, `endIndex` is always `1`.
@inlinable // trivial-implementation
public var endIndex: Index {
return 1
}
/// Returns the position immediately after the given index.
///
/// - Parameter i: A valid index of the collection. `i` must be `0`.
/// - Returns: The index value immediately after `i`.
@inlinable // trivial-implementation
public func index(after i: Index) -> Index {
_precondition(i == startIndex)
return 1
}
/// Returns the position immediately before the given index.
///
/// - Parameter i: A valid index of the collection. `i` must be `1`.
/// - Returns: The index value immediately before `i`.
@inlinable // trivial-implementation
public func index(before i: Index) -> Index {
_precondition(i == endIndex)
return 0
}
/// Returns an iterator over the elements of this collection.
///
/// - Complexity: O(1)
@inlinable // trivial-implementation
public __consuming func makeIterator() -> Iterator {
return Iterator(_elements: _element)
}
/// Accesses the element at the specified position.
///
/// - Parameter position: The position of the element to access. The only
/// valid position in a `CollectionOfOne` instance is `0`.
@inlinable // trivial-implementation
public subscript(position: Int) -> Element {
_read {
_precondition(position == 0, "Index out of range")
yield _element
}
_modify {
_precondition(position == 0, "Index out of range")
yield &_element
}
}
@inlinable // trivial-implementation
public subscript(bounds: Range<Int>) -> SubSequence {
get {
_failEarlyRangeCheck(bounds, bounds: 0..<1)
return Slice(base: self, bounds: bounds)
}
set {
_failEarlyRangeCheck(bounds, bounds: 0..<1)
let n = newValue.count
_precondition(bounds.count == n, "CollectionOfOne can't be resized")
if n == 1 { self = newValue.base }
}
}
/// The number of elements in the collection, which is always one.
@inlinable // trivial-implementation
public var count: Int {
return 1
}
}
extension CollectionOfOne: CustomDebugStringConvertible {
/// A textual representation of the collection, suitable for debugging.
public var debugDescription: String {
return "CollectionOfOne(\(String(reflecting: _element)))"
}
}
extension CollectionOfOne: CustomReflectable {
public var customMirror: Mirror {
return Mirror(self, children: ["element": _element])
}
}
extension CollectionOfOne: ConcurrentValue where Element: ConcurrentValue { }
extension CollectionOfOne.Iterator: ConcurrentValue where Element: ConcurrentValue { }