blob: 908206956a3372694e475fe911b4b474e16e6611 [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
//
/**************** Immutable Ordered Set ****************/
open class NSOrderedSet: NSObject, NSCopying, NSMutableCopying, NSSecureCoding, ExpressibleByArrayLiteral {
fileprivate var _storage: NSSet
fileprivate var _orderedStorage: NSArray
open override func copy() -> Any {
return copy(with: nil)
}
open func copy(with zone: NSZone? = nil) -> Any {
if type(of: self) === NSOrderedSet.self {
return self
} else {
return NSOrderedSet(storage: self.set as NSSet, orderedStorage: self.array as NSArray)
}
}
open override func mutableCopy() -> Any {
return mutableCopy(with: nil)
}
open func mutableCopy(with zone: NSZone? = nil) -> Any {
if type(of: self) === NSOrderedSet.self || type(of: self) === NSMutableOrderedSet.self {
let mutableOrderedSet = NSMutableOrderedSet()
mutableOrderedSet._mutableStorage._storage = self._storage._storage
mutableOrderedSet._storage = mutableOrderedSet._mutableStorage
mutableOrderedSet._mutableOrderedStorage._storage = self._orderedStorage._storage
mutableOrderedSet._orderedStorage = mutableOrderedSet._mutableOrderedStorage
return mutableOrderedSet
} else {
let count = self.count
let mutableSet = NSMutableSet(capacity: count)
let mutableArray = NSMutableArray(capacity: count)
for obj in self {
mutableSet.add(obj)
mutableArray.add(obj)
}
return NSMutableOrderedSet(mutableStorage: mutableSet, mutableOrderedStorage: mutableArray)
}
}
public static var supportsSecureCoding: Bool {
return true
}
open override func isEqual(_ object: Any?) -> Bool {
guard let orderedSet = object as? NSOrderedSet else { return false }
return isEqual(to: orderedSet)
}
open func encode(with aCoder: NSCoder) {
guard aCoder.allowsKeyedCoding else {
preconditionFailure("Unkeyed coding is unsupported.")
}
for idx in _indices {
aCoder.encode(__SwiftValue.store(self.object(at: idx)), forKey:"NS.object.\(idx)")
}
}
public required convenience init?(coder aDecoder: NSCoder) {
// This uses the same storage setup as NSSet, but without allowing the use of the "NS.objects" key:
self.init(array: NSSet._objects(from: aDecoder, allowDecodingNonindexedArrayKey: false))
}
open var count: Int {
return _storage.count
}
open func object(at idx: Int) -> Any {
_validateSubscript(idx)
return _orderedStorage.object(at: idx)
}
open func index(of object: Any) -> Int {
return _orderedStorage.index(of: object)
}
public convenience override init() {
self.init(objects: [], count: 0)
}
public init(objects: UnsafePointer<AnyObject>?, count cnt: Int) {
let storage = NSSet(objects: objects, count: cnt)
_storage = storage
let orderedStorage = NSMutableArray()
let buffer = UnsafeBufferPointer(start: objects, count: cnt)
for obj in buffer where storage.contains(obj) {
orderedStorage.add(obj)
}
_orderedStorage = orderedStorage.copy() as! NSArray
super.init()
}
required public convenience init(arrayLiteral elements: Any...) {
self.init(array: elements)
}
public convenience init(objects elements: Any...) {
self.init(array: elements)
}
internal init(storage: NSSet, orderedStorage: NSArray) {
_storage = storage
_orderedStorage = orderedStorage
}
open subscript (idx: Int) -> Any {
return object(at: idx)
}
internal var allObjects: [Any] {
return _orderedStorage.allObjects
}
/// The range of indices that are valid for subscripting the ordered set.
internal var _indices: Range<Int> {
return 0..<count
}
/// Checks that an index is valid for subscripting: 0 ≤ `index` < `count`.
internal func _validateSubscript(_ index: Int, file: StaticString = #file, line: UInt = #line) {
precondition(_indices.contains(index), "\(self): Index out of bounds", file: file, line: line)
}
/// Returns an array with the objects at the specified indexes in the
/// ordered set.
///
/// - Parameter indexes: The indexes.
/// - Returns: An array of objects in the ascending order of their indexes
/// in `indexes`.
///
/// - Complexity: O(*n*), where *n* is the number of indexes in `indexes`.
/// - Precondition: The indexes in `indexes` are within the
/// bounds of the ordered set.
open func objects(at indexes: IndexSet) -> [Any] {
return indexes.map { object(at: $0) }
}
public var firstObject: Any? {
return _orderedStorage.firstObject
}
public var lastObject: Any? {
return _orderedStorage.lastObject
}
open func isEqual(to other: NSOrderedSet) -> Bool {
if count != other.count {
return false
}
for idx in _indices {
if let value1 = object(at: idx) as? AnyHashable,
let value2 = other.object(at: idx) as? AnyHashable {
if value1 != value2 {
return false
}
}
}
return true
}
open func contains(_ object: Any) -> Bool {
return _storage.contains(object)
}
open func intersects(_ other: NSOrderedSet) -> Bool {
if count < other.count {
return contains { obj in other.contains(obj) }
} else {
return other.contains { obj in contains(obj) }
}
}
open func intersectsSet(_ set: Set<AnyHashable>) -> Bool {
if count < set.count {
return contains { obj in set.contains(obj) }
} else {
return set.contains { obj in contains(obj) }
}
}
open func isSubset(of other: NSOrderedSet) -> Bool {
// If self is larger then self cannot be a subset of other
if count > other.count {
return false
}
for item in self {
if !other.contains(item) {
return false
}
}
return true
}
open func isSubset(of set: Set<AnyHashable>) -> Bool {
// If self is larger then self cannot be a subset of set
if count > set.count {
return false
}
for item in self {
if !set.contains(item as! AnyHashable) {
return false
}
}
return true
}
public func objectEnumerator() -> NSEnumerator {
return _orderedStorage.objectEnumerator()
}
public func reverseObjectEnumerator() -> NSEnumerator {
return _orderedStorage.reverseObjectEnumerator()
}
/*@NSCopying*/
public var reversed: NSOrderedSet {
return NSOrderedSet(array: _orderedStorage.reversed())
}
// These two methods return a facade object for the receiving ordered set,
// which acts like an immutable array or set (respectively). Note that
// while you cannot mutate the ordered set through these facades, mutations
// to the original ordered set will "show through" the facade and it will
// appear to change spontaneously, since a copy of the ordered set is not
// being made.
public var array: [Any] {
if type(of: self) === NSOrderedSet.self || type(of: self) === NSMutableOrderedSet.self {
return _orderedStorage._swiftObject
} else {
var result: [Any] = []
result.reserveCapacity(self.count)
for obj in self {
result.append(obj)
}
return result
}
}
public var set: Set<AnyHashable> {
if type(of: self) === NSOrderedSet.self || type(of: self) === NSMutableOrderedSet.self {
return _storage._swiftObject
} else {
var result: Set<AnyHashable> = []
result.reserveCapacity(self.count)
for obj in self {
result.insert(obj as! AnyHashable)
}
return result
}
}
open func enumerateObjects(_ block: (Any, Int, UnsafeMutablePointer<ObjCBool>) -> Swift.Void) {
_orderedStorage.enumerateObjects(block)
}
open func enumerateObjects(options opts: NSEnumerationOptions = [], using block: (Any, Int, UnsafeMutablePointer<ObjCBool>) -> Swift.Void) {
enumerateObjects(at: IndexSet(0..<count), options: opts, using: block)
}
open func enumerateObjects(at s: IndexSet, options opts: NSEnumerationOptions = [], using block: (Any, Int, UnsafeMutablePointer<ObjCBool>) -> Swift.Void) {
_orderedStorage.enumerateObjects(options: opts, using: block)
}
open func index(ofObjectPassingTest predicate: (Any, Int, UnsafeMutablePointer<ObjCBool>) -> Bool) -> Int {
return index([], ofObjectPassingTest: predicate)
}
open func index(_ opts: NSEnumerationOptions = [], ofObjectPassingTest predicate: (Any, Int, UnsafeMutablePointer<ObjCBool>) -> Bool) -> Int {
return index(ofObjectAt: IndexSet(0..<count), options: [], passingTest: predicate)
}
open func index(ofObjectAt s: IndexSet, options opts: NSEnumerationOptions = [], passingTest predicate: (Any, Int, UnsafeMutablePointer<ObjCBool>) -> Bool) -> Int {
return _orderedStorage.indexOfObject(at: s, options: opts, passingTest: predicate)
}
open func indexes(ofObjectsPassingTest predicate: (Any, Int, UnsafeMutablePointer<ObjCBool>) -> Bool) -> IndexSet {
return indexes(ofObjectsAt: IndexSet(0..<count), options: [], passingTest: predicate)
}
open func indexes(options opts: NSEnumerationOptions = [], ofObjectsPassingTest predicate: (Any, Int, UnsafeMutablePointer<ObjCBool>) -> Bool) -> IndexSet {
return indexes(ofObjectsAt: IndexSet(0..<count), options: opts, passingTest: predicate)
}
open func indexes(ofObjectsAt s: IndexSet, options opts: NSEnumerationOptions = [], passingTest predicate: (Any, Int, UnsafeMutablePointer<ObjCBool>) -> Bool) -> IndexSet {
return _orderedStorage.indexesOfObjects(at: s, options: opts, passingTest: predicate)
}
// binary search
open func index(of object: Any, inSortedRange range: NSRange, options opts: NSBinarySearchingOptions = [], usingComparator cmp: (Any, Any) -> ComparisonResult) -> Int {
return _orderedStorage.index(of:object, inSortedRange: range, options: opts, usingComparator: cmp)
}
open func sortedArray(comparator cmptr: (Any, Any) -> ComparisonResult) -> [Any] {
return sortedArray(options: [], usingComparator: cmptr)
}
open func sortedArray(options opts: NSSortOptions = [], usingComparator cmptr: (Any, Any) -> ComparisonResult) -> [Any] {
return _orderedStorage.sortedArray(options: opts, usingComparator: cmptr)
}
override open var description: String {
return description(withLocale: nil)
}
public func description(withLocale locale: Locale?) -> String {
return description(withLocale: locale, indent: 0)
}
public func description(withLocale locale: Locale?, indent level: Int) -> String {
return _orderedStorage.description(withLocale: locale, indent: level)
}
public convenience init(object: Any) {
self.init(array: [object])
}
public convenience init(orderedSet set: NSOrderedSet) {
self.init(orderedSet: set, copyItems: false)
}
public convenience init(orderedSet set: NSOrderedSet, copyItems flag: Bool) {
self.init(orderedSet: set, range: NSRange(location: 0, length: set.count), copyItems: flag)
}
public convenience init(orderedSet set: NSOrderedSet, range: NSRange, copyItems flag: Bool) {
// TODO: Use the array method here when available.
self.init(array: Array(set), range: range, copyItems: flag)
}
public convenience init(array: [Any]) {
let buffer = UnsafeMutablePointer<AnyObject>.allocate(capacity: array.count)
for (idx, element) in array.enumerated() {
buffer.advanced(by: idx).initialize(to: __SwiftValue.store(element))
}
self.init(objects: buffer, count: array.count)
buffer.deinitialize(count: array.count)
buffer.deallocate()
}
public convenience init(array set: [Any], copyItems flag: Bool) {
self.init(array: set, range: NSRange(location: 0, length: set.count), copyItems: flag)
}
public convenience init(array set: [Any], range: NSRange, copyItems flag: Bool) {
var objects = set
if let range = Range(range), range.count != set.count || flag {
objects = [Any]()
for index in range.indices {
let object = set[index]
objects.append(flag ? (object as! NSObject).copy() : object)
}
}
self.init(array: objects)
}
public convenience init(set: Set<AnyHashable>) {
self.init(set: set, copyItems: false)
}
public convenience init(set: Set<AnyHashable>, copyItems flag: Bool) {
self.init(array: Array(set), copyItems: flag)
}
open func sortedArray(using sortDescriptors: [NSSortDescriptor]) -> [Any] {
return self.array._nsObject.sortedArray(using: sortDescriptors)
}
}
/**************** Mutable Ordered Set ****************/
open class NSMutableOrderedSet: NSOrderedSet {
fileprivate var _mutableStorage: NSMutableSet
fileprivate var _mutableOrderedStorage: NSMutableArray
public override init(objects: UnsafePointer<AnyObject>?, count cnt: Int) {
let storage = NSMutableSet(objects: objects, count: cnt)
_mutableStorage = storage
let orderedStorage = NSMutableArray()
let buffer = UnsafeBufferPointer(start: objects, count: cnt)
for obj in buffer where storage.contains(obj) {
orderedStorage.add(obj)
}
_mutableOrderedStorage = orderedStorage
super.init(storage: storage, orderedStorage: orderedStorage)
}
open func insert(_ object: Any, at idx: Int) {
precondition(idx <= count && idx >= 0, "\(self): Index out of bounds")
if contains(object) {
return
}
_mutableStorage.add(object)
_mutableOrderedStorage.insert(object, at: idx)
}
open func removeObject(at idx: Int) {
_validateSubscript(idx)
_mutableStorage.remove(_orderedStorage[idx])
_mutableOrderedStorage.removeObject(at: idx)
}
open func replaceObject(at idx: Int, with obj: Any) {
let objectToReplace = object(at: idx)
_mutableStorage.remove(objectToReplace)
_mutableStorage.add(obj)
_mutableOrderedStorage.replaceObject(at: idx, with: obj)
}
public init(capacity numItems: Int) {
_mutableStorage = NSMutableSet(capacity: numItems)
_mutableOrderedStorage = NSMutableArray(capacity: numItems)
super.init(objects: [], count: 0)
_storage = _mutableStorage
_orderedStorage = _mutableOrderedStorage
}
required public convenience init(arrayLiteral elements: Any...) {
self.init(capacity: 0)
addObjects(from: elements)
}
fileprivate init(mutableStorage: NSMutableSet, mutableOrderedStorage: NSMutableArray) {
_mutableStorage = mutableStorage
_mutableOrderedStorage = mutableOrderedStorage
super.init(objects: [], count: 0)
_storage = _mutableStorage
_orderedStorage = _mutableOrderedStorage
}
public required convenience init?(coder aDecoder: NSCoder) {
// See NSOrderedSet.init?(coder:)
self.init(array: NSSet._objects(from: aDecoder, allowDecodingNonindexedArrayKey: false))
}
open override func copy(with zone: NSZone? = nil) -> Any {
if type(of: self) === NSMutableOrderedSet.self {
let orderedSet = NSOrderedSet()
orderedSet._storage._storage = self._storage._storage
orderedSet._orderedStorage._storage = self._orderedStorage._storage
return orderedSet
} else {
return NSMutableOrderedSet(mutableStorage: NSMutableSet(set: self.set), mutableOrderedStorage: NSMutableArray(array: self.array))
}
}
fileprivate func _removeObject(_ object: Any) {
guard contains(object) else {
return
}
_mutableStorage.remove(object)
_mutableOrderedStorage.remove(object)
}
fileprivate func _insertObject(_ object: Any) {
if contains(object) {
return
}
_mutableStorage.add(object)
_mutableOrderedStorage.add(object)
}
open override subscript(idx: Int) -> Any {
get {
return object(at: idx)
}
set {
replaceObject(at: idx, with: newValue)
}
}
open func add(_ object: Any) {
_insertObject(object)
}
open func add(_ objects: UnsafePointer<AnyObject>?, count: Int) {
let buffer = UnsafeBufferPointer(start: objects, count: count)
for obj in buffer {
_insertObject(obj)
}
}
open func addObjects(from array: [Any]) {
for object in array {
_insertObject(object)
}
}
open func exchangeObject(at idx1: Int, withObjectAt idx2: Int) {
_mutableOrderedStorage.exchangeObject(at: idx1, withObjectAt: idx2)
}
open func moveObjects(at indexes: IndexSet, to idx: Int) {
var removedObjects = [Any]()
for index in indexes.lazy.reversed() {
let obj = object(at: index)
removedObjects.append(obj)
removeObject(at: index)
}
for removedObject in removedObjects {
insert(removedObject, at: idx)
}
}
open func insert(_ objects: [Any], at indexes: IndexSet) {
for (indexLocation, index) in indexes.enumerated() {
let object = objects[indexLocation]
insert(object, at: index)
}
}
/// Sets the object at the specified index of the mutable ordered set.
///
/// - Parameters:
/// - obj: The object to be set.
/// - idx: The index. If the index is equal to `count`, then it appends
/// the object. Otherwise it replaces the object at the index with the
/// given object.
open func setObject(_ obj: Any, at idx: Int) {
if idx == count {
insert(obj, at: idx)
} else {
replaceObject(at: idx, with: obj)
}
}
open func replaceObjects(in range: NSRange, with objects: UnsafePointer<AnyObject>!, count: Int) {
if let range = Range(range) {
let buffer = UnsafeBufferPointer(start: objects, count: count)
for (indexLocation, index) in range.indices.lazy.reversed().enumerated() {
let object = buffer[indexLocation]
replaceObject(at: index, with: object)
}
}
}
open func replaceObjects(at indexes: IndexSet, with objects: [Any]) {
for (indexLocation, index) in indexes.enumerated() {
let object = objects[indexLocation]
replaceObject(at: index, with: object)
}
}
open func removeObjects(in range: NSRange) {
if let range = Range(range) {
for index in range.indices.lazy.reversed() {
removeObject(at: index)
}
}
}
open func removeObjects(at indexes: IndexSet) {
for index in indexes.lazy.reversed() {
removeObject(at: index)
}
}
open func removeAllObjects() {
_mutableStorage.removeAllObjects()
_mutableOrderedStorage.removeAllObjects()
}
open func remove(_ val: Any) {
_mutableStorage.remove(val)
_mutableOrderedStorage.remove(val)
}
open func removeObjects(in array: [Any]) {
array.forEach(remove)
}
open func intersect(_ other: NSOrderedSet) {
var i = 0
while i < _mutableOrderedStorage.count {
let currentObject = _mutableOrderedStorage[i] as! AnyHashable
if !other.contains(currentObject) {
let nextIndex = i + 1
if nextIndex < count {
_mutableOrderedStorage[i] = _mutableOrderedStorage[nextIndex]
}
_mutableStorage.remove(currentObject)
} else {
i += 1
}
}
while _mutableOrderedStorage.count > count {
_mutableOrderedStorage.removeLastObject()
}
}
open func minus(_ other: NSOrderedSet) {
for item in other where contains(item) {
remove(item)
}
}
open func union(_ other: NSOrderedSet) {
other.forEach(add)
}
open func intersectSet(_ other: Set<AnyHashable>) {
let objects = Array(self)
for case let item as AnyHashable in objects where !other.contains(item) {
remove(item)
}
}
open func minusSet(_ other: Set<AnyHashable>) {
for item in other where contains(item) {
remove(item)
}
}
open func unionSet(_ other: Set<AnyHashable>) {
other.forEach(add)
}
open func sort(comparator cmptr: (Any, Any) -> ComparisonResult) {
sortRange(NSRange(location: 0, length: count), options: [], usingComparator: cmptr)
}
open func sort(options opts: NSSortOptions = [], usingComparator cmptr: (Any, Any) -> ComparisonResult) {
sortRange(NSRange(location: 0, length: count), options: opts, usingComparator: cmptr)
}
open func sortRange(_ range: NSRange, options opts: NSSortOptions = [], usingComparator cmptr: (Any, Any) -> ComparisonResult) {
let sortedSubrange = _mutableOrderedStorage.sortedArray(from: range, options: opts, usingComparator: cmptr)
_mutableOrderedStorage.replaceObjects(in: range, withObjectsFrom: sortedSubrange)
}
open func sort(using sortDescriptors: [NSSortDescriptor]) {
_mutableOrderedStorage.sort(using: sortDescriptors)
}
// MARK: Convenience initializers that are automatically inherited in ObjC, but not in Swift:
public convenience init() {
self.init(objects: [], count: 0)
}
public convenience init(object: Any) {
self.init(array: [object])
}
public convenience init(orderedSet set: NSOrderedSet) {
self.init(orderedSet: set, copyItems: false)
}
public convenience init(orderedSet set: NSOrderedSet, copyItems flag: Bool) {
self.init(orderedSet: set, range: NSRange(location: 0, length: set.count), copyItems: flag)
}
public convenience init(orderedSet set: NSOrderedSet, range: NSRange, copyItems flag: Bool) {
// TODO: Use the array method here when available.
self.init(array: Array(set), range: range, copyItems: flag)
}
public convenience init(array: [Any]) {
let buffer = UnsafeMutablePointer<AnyObject>.allocate(capacity: array.count)
for (idx, element) in array.enumerated() {
buffer.advanced(by: idx).initialize(to: __SwiftValue.store(element))
}
self.init(objects: buffer, count: array.count)
buffer.deinitialize(count: array.count)
buffer.deallocate()
}
public convenience init(array set: [Any], copyItems flag: Bool) {
self.init(array: set, range: NSRange(location: 0, length: set.count), copyItems: flag)
}
public convenience init(array set: [Any], range: NSRange, copyItems flag: Bool) {
var objects = set
if let range = Range(range), range.count != set.count || flag {
objects = [Any]()
for index in range.indices {
let object = set[index]
objects.append(flag ? (object as! NSObject).copy() : object)
}
}
self.init(array: objects)
}
public convenience init(set: Set<AnyHashable>) {
self.init(set: set, copyItems: false)
}
public convenience init(set: Set<AnyHashable>, copyItems flag: Bool) {
self.init(array: Array(set), copyItems: flag)
}
public convenience init(objects elements: Any...) {
self.init(array: elements)
}
}
extension NSOrderedSet: Sequence {
public typealias Iterator = NSEnumerator.Iterator
/// Return a *generator* over the elements of this *sequence*.
///
/// - Complexity: O(1).
public func makeIterator() -> Iterator {
return self.objectEnumerator().makeIterator()
}
}
extension NSOrderedSet: CustomReflectable {
public var customMirror: Mirror {
return Mirror(reflecting: _orderedStorage as Array)
}
}