blob: 748c03a080581ad0c84fa3de81a585e2474e2aa8 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#if DEPLOYMENT_RUNTIME_SWIFT
func _NSIndexPathCreateFromIndexes(_ idx1: Int, _ idx2: Int) -> NSObject {
var indexes = (idx1, idx2)
return withUnsafeBytes(of: &indexes) { (ptr) -> NSIndexPath in
return NSIndexPath.init(indexes: ptr.baseAddress!.assumingMemoryBound(to: Int.self), length: 2)
}
}
#else
@_exported import Foundation // Clang module
import _SwiftFoundationOverlayShims
#endif
/**
`IndexPath` represents the path to a specific node in a tree of nested array collections.
Each index in an index path represents the index into an array of children from one node in the tree to another, deeper, node.
*/
public struct IndexPath : ReferenceConvertible, Equatable, Hashable, MutableCollection, RandomAccessCollection, Comparable, ExpressibleByArrayLiteral {
public typealias ReferenceType = NSIndexPath
public typealias Element = Int
public typealias Index = Array<Int>.Index
public typealias Indices = DefaultRandomAccessIndices<IndexPath>
fileprivate enum Storage : ExpressibleByArrayLiteral {
typealias Element = Int
case empty
case single(Int)
case pair(Int, Int)
case array([Int])
init(arrayLiteral elements: Int...) {
self.init(elements)
}
init(_ elements: [Int]) {
switch elements.count {
case 0:
self = .empty
break
case 1:
self = .single(elements[0])
break
case 2:
self = .pair(elements[0], elements[1])
break
default:
self = .array(elements)
break
}
}
func dropLast() -> Storage {
switch self {
case .empty:
return .empty
case .single(_):
return .empty
case .pair(let first, _):
return .single(first)
case .array(let indexes):
switch indexes.count {
case 3:
return .pair(indexes[0], indexes[1])
default:
return .array(Array<Int>(indexes.dropLast()))
}
}
}
mutating func append(_ other: Int) {
switch self {
case .empty:
self = .single(other)
break
case .single(let first):
self = .pair(first, other)
break
case .pair(let first, let second):
self = .array([first, second, other])
break
case .array(let indexes):
self = .array(indexes + [other])
break
}
}
mutating func append(contentsOf other: Storage) {
switch self {
case .empty:
switch other {
case .empty:
// DO NOTHING
break
case .single(let rhsIndex):
self = .single(rhsIndex)
break
case .pair(let rhsFirst, let rhsSecond):
self = .pair(rhsFirst, rhsSecond)
break
case .array(let rhsIndexes):
self = .array(rhsIndexes)
break
}
break
case .single(let lhsIndex):
switch other {
case .empty:
// DO NOTHING
break
case .single(let rhsIndex):
self = .pair(lhsIndex, rhsIndex)
break
case .pair(let rhsFirst, let rhsSecond):
self = .array([lhsIndex, rhsFirst, rhsSecond])
break
case .array(let rhsIndexes):
self = .array([lhsIndex] + rhsIndexes)
break
}
break
case .pair(let lhsFirst, let lhsSecond):
switch other {
case .empty:
// DO NOTHING
break
case .single(let rhsIndex):
self = .array([lhsFirst, lhsSecond, rhsIndex])
break
case .pair(let rhsFirst, let rhsSecond):
self = .array([lhsFirst, lhsSecond, rhsFirst, rhsSecond])
break
case .array(let rhsIndexes):
self = .array([lhsFirst, lhsSecond] + rhsIndexes)
break
}
break
case .array(let lhsIndexes):
switch other {
case .empty:
// DO NOTHING
break
case .single(let rhsIndex):
self = .array(lhsIndexes + [rhsIndex])
break
case .pair(let rhsFirst, let rhsSecond):
self = .array(lhsIndexes + [rhsFirst, rhsSecond])
break
case .array(let rhsIndexes):
self = .array(lhsIndexes + rhsIndexes)
break
}
break
}
}
mutating func append(contentsOf other: [Int]) {
switch self {
case .empty:
switch other.count {
case 0:
// DO NOTHING
break
case 1:
self = .single(other[0])
break
case 2:
self = .pair(other[0], other[1])
break
default:
self = .array(other)
break
}
break
case .single(let first):
switch other.count {
case 0:
// DO NOTHING
break
case 1:
self = .pair(first, other[0])
break
default:
self = .array([first] + other)
break
}
break
case .pair(let first, let second):
switch other.count {
case 0:
// DO NOTHING
break
default:
self = .array([first, second] + other)
break
}
break
case .array(let indexes):
self = .array(indexes + other)
break
}
}
subscript(_ index: Int) -> Int {
get {
switch self {
case .empty:
fatalError("index \(index) out of bounds of count 0")
break
case .single(let first):
precondition(index == 0, "index \(index) out of bounds of count 1")
return first
case .pair(let first, let second):
precondition(index >= 0 && index < 2, "index \(index) out of bounds of count 2")
return index == 0 ? first : second
case .array(let indexes):
return indexes[index]
}
}
set {
switch self {
case .empty:
fatalError("index \(index) out of bounds of count 0")
break
case .single(_):
precondition(index == 0, "index \(index) out of bounds of count 1")
self = .single(newValue)
break
case .pair(let first, let second):
precondition(index >= 0 && index < 2, "index \(index) out of bounds of count 2")
if index == 0 {
self = .pair(newValue, second)
} else {
self = .pair(first, newValue)
}
break
case .array(let indexes_):
var indexes = indexes_
indexes[index] = newValue
self = .array(indexes)
break
}
}
}
subscript(range: Range<Index>) -> Storage {
get {
switch self {
case .empty:
switch (range.lowerBound, range.upperBound) {
case (0, 0):
return .empty
default:
fatalError("range \(range) is out of bounds of count 0")
}
case .single(let index):
switch (range.lowerBound, range.upperBound) {
case (0, 0): fallthrough
case (1, 1):
return .empty
case (0, 1):
return .single(index)
default:
fatalError("range \(range) is out of bounds of count 1")
}
return self
case .pair(let first, let second):
switch (range.lowerBound, range.upperBound) {
case (0, 0):
fallthrough
case (1, 1):
fallthrough
case (2, 2):
return .empty
case (0, 1):
return .single(first)
case (1, 2):
return .single(second)
case (0, 2):
return self
default:
fatalError("range \(range) is out of bounds of count 2")
}
case .array(let indexes):
let slice = indexes[range]
switch slice.count {
case 0:
return .empty
case 1:
return .single(slice[0])
case 2:
return .pair(slice[0], slice[1])
default:
return .array(Array<Int>(slice))
}
}
}
set {
switch self {
case .empty:
precondition(range.lowerBound == 0 && range.upperBound == 0, "range \(range) is out of bounds of count 0")
self = newValue
break
case .single(let index):
switch (range.lowerBound, range.upperBound, newValue) {
case (0, 0, .empty):
fallthrough
case (1, 1, .empty):
break
case (0, 0, .single(let other)):
self = .pair(other, index)
break
case (0, 0, .pair(let first, let second)):
self = .array([first, second, index])
break
case (0, 0, .array(let other)):
self = .array(other + [index])
break
case (0, 1, .empty):
fallthrough
case (0, 1, .single):
fallthrough
case (0, 1, .pair):
fallthrough
case (0, 1, .array):
self = newValue
case (1, 1, .single(let other)):
self = .pair(index, other)
break
case (1, 1, .pair(let first, let second)):
self = .array([index, first, second])
break
case (1, 1, .array(let other)):
self = .array([index] + other)
break
default:
fatalError("range \(range) is out of bounds of count 1")
}
case .pair(let first, let second):
switch (range.lowerBound, range.upperBound) {
case (0, 0):
switch newValue {
case .empty:
break
case .single(let other):
self = .array([other, first, second])
break
case .pair(let otherFirst, let otherSecond):
self = .array([otherFirst, otherSecond, first, second])
break
case .array(let other):
self = .array(other + [first, second])
break
}
break
case (0, 1):
switch newValue {
case .empty:
self = .single(second)
break
case .single(let other):
self = .pair(other, second)
break
case .pair(let otherFirst, let otherSecond):
self = .array([otherFirst, otherSecond, second])
break
case .array(let other):
self = .array(other + [second])
break
}
break
case (0, 2):
self = newValue
break
case (1, 2):
switch newValue {
case .empty:
self = .single(first)
break
case .single(let other):
self = .pair(first, other)
break
case .pair(let otherFirst, let otherSecond):
self = .array([first, otherFirst, otherSecond])
break
case .array(let other):
self = .array([first] + other)
}
break
case (2, 2):
switch newValue {
case .empty:
break
case .single(let other):
self = .array([first, second, other])
break
case .pair(let otherFirst, let otherSecond):
self = .array([first, second, otherFirst, otherSecond])
break
case .array(let other):
self = .array([first, second] + other)
}
break
default:
fatalError("range \(range) is out of bounds of count 2")
}
case .array(let indexes):
var newIndexes = indexes
newIndexes.removeSubrange(range)
switch newValue {
case .empty:
break
case .single(let index):
newIndexes.insert(index, at: range.lowerBound)
break
case .pair(let first, let second):
newIndexes.insert(first, at: range.lowerBound)
newIndexes.insert(second, at: range.lowerBound + 1)
break
case .array(let other):
newIndexes.insert(contentsOf: other, at: range.lowerBound)
break
}
self = Storage(newIndexes)
break
}
}
}
var count: Int {
switch self {
case .empty:
return 0
case .single:
return 1
case .pair:
return 2
case .array(let indexes):
return indexes.count
}
}
var startIndex: Int {
return 0
}
var endIndex: Int {
return count
}
var allValues: [Int] {
switch self {
case .empty: return []
case .single(let index): return [index]
case .pair(let first, let second): return [first, second]
case .array(let indexes): return indexes
}
}
func index(before i: Int) -> Int {
return i - 1
}
func index(after i: Int) -> Int {
return i + 1
}
var description: String {
switch self {
case .empty:
return "[]"
case .single(let index):
return "[\(index)]"
case .pair(let first, let second):
return "[\(first), \(second)]"
case .array(let indexes):
return indexes.description
}
}
func withUnsafeBufferPointer<R>(_ body: (UnsafeBufferPointer<Int>) throws -> R) rethrows -> R {
switch self {
case .empty:
return try body(UnsafeBufferPointer<Int>(start: nil, count: 0))
case .single(let index_):
var index = index_
return try withUnsafePointer(to: &index) { (start) throws -> R in
return try body(UnsafeBufferPointer<Int>(start: start, count: 1))
}
case .pair(let first, let second):
var pair = (first, second)
return try withUnsafeBytes(of: &pair) { (rawBuffer: UnsafeRawBufferPointer) throws -> R in
return try body(UnsafeBufferPointer<Int>(start: rawBuffer.baseAddress?.assumingMemoryBound(to: Int.self), count: 2))
}
case .array(let indexes):
return try indexes.withUnsafeBufferPointer(body)
}
}
var debugDescription: String { return description }
static func +(_ lhs: Storage, _ rhs: Storage) -> Storage {
var res = lhs
res.append(contentsOf: rhs)
return res
}
static func +(_ lhs: Storage, _ rhs: [Int]) -> Storage {
var res = lhs
res.append(contentsOf: rhs)
return res
}
static func ==(_ lhs: Storage, _ rhs: Storage) -> Bool {
switch (lhs, rhs) {
case (.empty, .empty):
return true
case (.single(let lhsIndex), .single(let rhsIndex)):
return lhsIndex == rhsIndex
case (.pair(let lhsFirst, let lhsSecond), .pair(let rhsFirst, let rhsSecond)):
return lhsFirst == rhsFirst && lhsSecond == rhsSecond
case (.array(let lhsIndexes), .array(let rhsIndexes)):
return lhsIndexes == rhsIndexes
default:
return false
}
}
}
fileprivate var _indexes : Storage
/// Initialize an empty index path.
public init() {
_indexes = []
}
/// Initialize with a sequence of integers.
public init<ElementSequence : Sequence>(indexes: ElementSequence)
where ElementSequence.Iterator.Element == Element {
_indexes = Storage(indexes.map { $0 })
}
/// Initialize with an array literal.
public init(arrayLiteral indexes: Element...) {
_indexes = Storage(indexes)
}
/// Initialize with an array of elements.
public init(indexes: Array<Element>) {
_indexes = Storage(indexes)
}
fileprivate init(storage: Storage) {
_indexes = storage
}
/// Initialize with a single element.
public init(index: Element) {
_indexes = [index]
}
/// Return a new `IndexPath` containing all but the last element.
public func dropLast() -> IndexPath {
return IndexPath(storage: _indexes.dropLast())
}
/// Append an `IndexPath` to `self`.
public mutating func append(_ other: IndexPath) {
_indexes.append(contentsOf: other._indexes)
}
/// Append a single element to `self`.
public mutating func append(_ other: Element) {
_indexes.append(other)
}
/// Append an array of elements to `self`.
public mutating func append(_ other: Array<Element>) {
_indexes.append(contentsOf: other)
}
/// Return a new `IndexPath` containing the elements in self and the elements in `other`.
public func appending(_ other: Element) -> IndexPath {
var result = _indexes
result.append(other)
return IndexPath(storage: result)
}
/// Return a new `IndexPath` containing the elements in self and the elements in `other`.
public func appending(_ other: IndexPath) -> IndexPath {
return IndexPath(storage: _indexes + other._indexes)
}
/// Return a new `IndexPath` containing the elements in self and the elements in `other`.
public func appending(_ other: Array<Element>) -> IndexPath {
return IndexPath(storage: _indexes + other)
}
public subscript(index: Index) -> Element {
get {
return _indexes[index]
}
set {
_indexes[index] = newValue
}
}
public subscript(range: Range<Index>) -> IndexPath {
get {
return IndexPath(storage: _indexes[range])
}
set {
_indexes[range] = newValue._indexes
}
}
public func makeIterator() -> IndexingIterator<IndexPath> {
return IndexingIterator(_elements: self)
}
public var count: Int {
return _indexes.count
}
public var startIndex: Index {
return _indexes.startIndex
}
public var endIndex: Index {
return _indexes.endIndex
}
public func index(before i: Index) -> Index {
return _indexes.index(before: i)
}
public func index(after i: Index) -> Index {
return _indexes.index(after: i)
}
/// Sorting an array of `IndexPath` using this comparison results in an array representing nodes in depth-first traversal order.
public func compare(_ other: IndexPath) -> ComparisonResult {
let thisLength = count
let otherLength = other.count
let length = Swift.min(thisLength, otherLength)
for idx in 0..<length {
let otherValue = other[idx]
let value = self[idx]
if value < otherValue {
return .orderedAscending
} else if value > otherValue {
return .orderedDescending
}
}
if thisLength > otherLength {
return .orderedDescending
} else if thisLength < otherLength {
return .orderedAscending
}
return .orderedSame
}
public var hashValue: Int {
func hashIndexes(first: Int, last: Int, count: Int) -> Int {
let totalBits = MemoryLayout<Int>.size * 8
let lengthBits = 8
let firstIndexBits = (totalBits - lengthBits) / 2
return count &+ (first << lengthBits) &+ (last << (lengthBits + firstIndexBits))
}
switch _indexes {
case .empty: return 0
case .single(let index): return index.hashValue
case .pair(let first, let second):
return hashIndexes(first: first, last: second, count: 2)
default:
let cnt = _indexes.count
return hashIndexes(first: _indexes[0], last: _indexes[cnt - 1], count: cnt)
}
}
// MARK: - Bridging Helpers
fileprivate init(nsIndexPath: ReferenceType) {
let count = nsIndexPath.length
if count == 0 {
_indexes = []
} else if count == 1 {
_indexes = .single(nsIndexPath.index(atPosition: 0))
} else if count == 2 {
_indexes = .pair(nsIndexPath.index(atPosition: 0), nsIndexPath.index(atPosition: 1))
} else {
var indexes = Array<Int>(repeating: 0, count: count)
indexes.withUnsafeMutableBufferPointer { (buffer: inout UnsafeMutableBufferPointer<Int>) -> Void in
nsIndexPath.getIndexes(buffer.baseAddress!, range: NSRange(location: 0, length: count))
}
_indexes = .array(indexes)
}
}
fileprivate func makeReference() -> ReferenceType {
switch _indexes {
case .empty:
return ReferenceType()
case .single(let index):
return ReferenceType(index: index)
case .pair(let first, let second):
return _NSIndexPathCreateFromIndexes(first, second) as! ReferenceType
default:
return _indexes.withUnsafeBufferPointer {
return ReferenceType(indexes: $0.baseAddress, length: $0.count)
}
}
}
public static func ==(lhs: IndexPath, rhs: IndexPath) -> Bool {
return lhs._indexes == rhs._indexes
}
public static func +(lhs: IndexPath, rhs: IndexPath) -> IndexPath {
return lhs.appending(rhs)
}
public static func +=(lhs: inout IndexPath, rhs: IndexPath) {
lhs.append(rhs)
}
public static func <(lhs: IndexPath, rhs: IndexPath) -> Bool {
return lhs.compare(rhs) == ComparisonResult.orderedAscending
}
public static func <=(lhs: IndexPath, rhs: IndexPath) -> Bool {
let order = lhs.compare(rhs)
return order == ComparisonResult.orderedAscending || order == ComparisonResult.orderedSame
}
public static func >(lhs: IndexPath, rhs: IndexPath) -> Bool {
return lhs.compare(rhs) == ComparisonResult.orderedDescending
}
public static func >=(lhs: IndexPath, rhs: IndexPath) -> Bool {
let order = lhs.compare(rhs)
return order == ComparisonResult.orderedDescending || order == ComparisonResult.orderedSame
}
}
extension IndexPath : CustomStringConvertible, CustomDebugStringConvertible, CustomReflectable {
public var description: String {
return _indexes.description
}
public var debugDescription: String {
return _indexes.debugDescription
}
public var customMirror: Mirror {
return Mirror(self, unlabeledChildren: self, displayStyle: .collection)
}
}
#if DEPLOYMENT_RUNTIME_SWIFT
internal typealias IndexPathBridgeType = _ObjectTypeBridgeable
#else
internal typealias IndexPathBridgeType = _ObjectiveCBridgeable
#endif
extension IndexPath : IndexPathBridgeType {
public static func _getObjectiveCType() -> Any.Type {
return NSIndexPath.self
}
@_semantics("convertToObjectiveC")
public func _bridgeToObjectiveC() -> NSIndexPath {
return makeReference()
}
public static func _forceBridgeFromObjectiveC(_ x: NSIndexPath, result: inout IndexPath?) {
result = IndexPath(nsIndexPath: x)
}
public static func _conditionallyBridgeFromObjectiveC(_ x: NSIndexPath, result: inout IndexPath?) -> Bool {
result = IndexPath(nsIndexPath: x)
return true
}
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSIndexPath?) -> IndexPath {
guard let src = source else { return IndexPath() }
return IndexPath(nsIndexPath: src)
}
}
extension NSIndexPath : _HasCustomAnyHashableRepresentation {
// Must be @nonobjc to avoid infinite recursion during bridging.
@nonobjc
public func _toCustomAnyHashable() -> AnyHashable? {
return AnyHashable(IndexPath(nsIndexPath: self))
}
}
extension IndexPath : Codable {
private enum CodingKeys : Int, CodingKey {
case indexes
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
var indexesContainer = try container.nestedUnkeyedContainer(forKey: .indexes)
var indexes = [Int]()
if let count = indexesContainer.count {
indexes.reserveCapacity(count)
}
while !indexesContainer.isAtEnd {
let index = try indexesContainer.decode(Int.self)
indexes.append(index)
}
self.init(indexes: indexes)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
var indexesContainer = container.nestedUnkeyedContainer(forKey: .indexes)
switch self._indexes {
case .empty:
break
case .single(let index):
try indexesContainer.encode(index)
case .pair(let first, let second):
try indexesContainer.encode(first)
try indexesContainer.encode(second)
case .array(let indexes):
try indexesContainer.encode(contentsOf: indexes)
}
}
}