//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// @_exported import Foundation // Clang module //===----------------------------------------------------------------------===// // Fast enumeration //===----------------------------------------------------------------------===// public struct NSFastEnumerationIterator : IteratorProtocol { var enumerable: NSFastEnumeration var objects: (Unmanaged?, Unmanaged?, Unmanaged?, Unmanaged?, Unmanaged?, Unmanaged?, Unmanaged?, Unmanaged?, Unmanaged?, Unmanaged?, Unmanaged?, Unmanaged?, Unmanaged?, Unmanaged?, Unmanaged?, Unmanaged?) = (nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) var state = NSFastEnumerationState(state: 0, itemsPtr: nil, mutationsPtr: _fastEnumerationStorageMutationsPtr, extra: (0, 0, 0, 0, 0)) var index = 0 var count = 0 var useObjectsBuffer = false public init(_ enumerable: NSFastEnumeration) { self.enumerable = enumerable } public mutating func next() -> Any? { if index + 1 > count { index = 0 // ensure NO ivars of self are actually captured let enumeratedObject = enumerable var localState = state var localObjects = objects (count, useObjectsBuffer) = withUnsafeMutablePointer(to: &localObjects) { let buffer = AutoreleasingUnsafeMutablePointer($0) return withUnsafeMutablePointer(to: &localState) { (statePtr: UnsafeMutablePointer) -> (Int, Bool) in let result = enumeratedObject.countByEnumerating(with: statePtr, objects: buffer, count: 16) if statePtr.pointee.itemsPtr == buffer { // Most cocoa classes will emit their own inner pointer buffers instead of traversing this path. Notable exceptions include NSDictionary and NSSet return (result, true) } else { // this is the common case for things like NSArray return (result, false) } } } state = localState // restore the state value objects = localObjects // copy the object pointers back to the self storage if count == 0 { return nil } } defer { index += 1 } if !useObjectsBuffer { return state.itemsPtr![index] } else { switch index { case 0: return objects.0!.takeUnretainedValue() case 1: return objects.1!.takeUnretainedValue() case 2: return objects.2!.takeUnretainedValue() case 3: return objects.3!.takeUnretainedValue() case 4: return objects.4!.takeUnretainedValue() case 5: return objects.5!.takeUnretainedValue() case 6: return objects.6!.takeUnretainedValue() case 7: return objects.7!.takeUnretainedValue() case 8: return objects.8!.takeUnretainedValue() case 9: return objects.9!.takeUnretainedValue() case 10: return objects.10!.takeUnretainedValue() case 11: return objects.11!.takeUnretainedValue() case 12: return objects.12!.takeUnretainedValue() case 13: return objects.13!.takeUnretainedValue() case 14: return objects.14!.takeUnretainedValue() case 15: return objects.15!.takeUnretainedValue() default: fatalError("Access beyond storage buffer") } } } } extension NSEnumerator : Sequence { /// Return an *iterator* over the *enumerator*. /// /// - Complexity: O(1). public func makeIterator() -> NSFastEnumerationIterator { return NSFastEnumerationIterator(self) } }