blob: 20e5bc2f77c351896ce2a9ca4620015c65688617 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// Implementation note: NSIndexPath is an efficient array of integers for Objective-C.
// For Swift, we bridge to this wrapper of Array<Int>. This gives us great Swift performance and interop with Objective-C.
/**
`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 var _indexes : Array<Int>
/// 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 = indexes.map { $0 }
}
/// Initialize with an array literal.
public init(arrayLiteral indexes: Element...) {
_indexes = indexes
}
/// Initialize with an array of elements.
public init(indexes: [Element]) {
_indexes = indexes
}
/// 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(indexes: _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: [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(indexes: result)
}
/// Return a new `IndexPath` containing the elements in self and the elements in `other`.
public func appending(_ other: IndexPath) -> IndexPath {
return IndexPath(indexes: _indexes + other._indexes)
}
/// Return a new `IndexPath` containing the elements in self and the elements in `other`.
public func appending(_ other: [Element]) -> IndexPath {
return IndexPath(indexes: _indexes + other)
}
public subscript(index: Index) -> Element {
get {
return _indexes[index]
}
set {
_indexes[index] = newValue
}
}
public subscript(range: Range<Index>) -> IndexPath {
get {
return IndexPath(indexes: _indexes[range])
}
set {
_indexes.replaceSubrange(range, with: 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 {
// This is temporary
let me = self.makeReference()
let other = other.makeReference()
return me.compare(IndexPath._unconditionallyBridgeFromObjectiveC(other))
}
public var hashValue: Int {
// This is temporary
let me = self.makeReference()
return me.hash
}
// MARK: - Bridging Helpers
fileprivate init(nsIndexPath: ReferenceType) {
let count = nsIndexPath.length
if count == 0 {
_indexes = []
} else {
var ptr = malloc(count * MemoryLayout<Element>.size)
defer { free(ptr) }
let elementPtr = ptr!.bindMemory(to: Element.self, capacity: count)
nsIndexPath.getIndexes(elementPtr, range: NSMakeRange(0, count))
let buffer = UnsafeBufferPointer(start: elementPtr, count: count)
_indexes = buffer.map { $0 }
}
}
fileprivate func makeReference() -> ReferenceType {
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 _indexes.customMirror
}
}
extension IndexPath : _ObjectTypeBridgeable {
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 {
return IndexPath(nsIndexPath: source!)
}
}
extension NSIndexPath : _HasCustomAnyHashableRepresentation {
// Must be @nonobjc to avoid infinite recursion during bridging.
@nonobjc
public func _toCustomAnyHashable() -> AnyHashable? {
return AnyHashable(IndexPath._unconditionallyBridgeFromObjectiveC(self))
}
}