Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parity: NSSortDescriptor & _CFSwiftArrayReplaceValues #2234

Merged
merged 2 commits into from
May 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ if(ENABLE_TESTING)
TestFoundation/TestNSRange.swift
TestFoundation/TestNSRegularExpression.swift
TestFoundation/TestNSSet.swift
TestFoundation/TestNSSortDescriptor.swift
TestFoundation/TestNSString.swift
TestFoundation/TestNSTextCheckingResult.swift
TestFoundation/TestNSURLRequest.swift
Expand Down
1 change: 1 addition & 0 deletions CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ struct _NSArrayBridge {
CFIndex (*_Nonnull count)(CFTypeRef obj);
_Nonnull CFTypeRef (*_Nonnull objectAtIndex)(CFTypeRef obj, CFIndex index);
void (*_Nonnull getObjects)(CFTypeRef array, CFRange range, CFTypeRef _Nullable *_Nonnull values);
Boolean (*_Nonnull isSubclassOfNSMutableArray)(CFTypeRef array);
};

struct _NSMutableArrayBridge {
Expand Down
7 changes: 5 additions & 2 deletions CoreFoundation/Collections.subproj/CFArray.c
Original file line number Diff line number Diff line change
Expand Up @@ -966,9 +966,12 @@ void CFArraySortValues(CFMutableArrayRef array, CFRange range, CFComparatorFunct
__CFArrayValidateRange(array, range, __PRETTY_FUNCTION__);
CFAssert1(NULL != comparator, __kCFLogAssertion, "%s(): pointer to comparator function may not be NULL", __PRETTY_FUNCTION__);
Boolean immutable = false;
if (CF_IS_OBJC(CFArrayGetTypeID(), array) || CF_IS_SWIFT(CFArrayGetTypeID(), array)) {
if (CF_IS_OBJC(CFArrayGetTypeID(), array)) {
BOOL result;
result = CF_OBJC_CALLV((NSMutableArray *)array, isKindOfClass:[NSMutableArray class]); // TODO: Fixme for swift (we need a isKindOfClass replacement: (array as? NSMutableArray) != nil)
result = CF_OBJC_CALLV((NSMutableArray *)array, isKindOfClass:[NSMutableArray class]);
immutable = !result;
} else if (CF_IS_SWIFT(CFArrayGetTypeID(), array)) {
Boolean result = __CFSwiftBridge.NSArray.isSubclassOfNSMutableArray(array);
immutable = !result;
} else if (__kCFArrayImmutable == __CFArrayGetType(array)) {
immutable = true;
Expand Down
4 changes: 4 additions & 0 deletions Foundation.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
03B6F5841F15F339004F25AF /* TestURLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B6F5831F15F339004F25AF /* TestURLProtocol.swift */; };
1513A8432044893F00539722 /* FileManager_XDG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1513A8422044893F00539722 /* FileManager_XDG.swift */; };
1520469B1D8AEABE00D02E36 /* HTTPServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1520469A1D8AEABE00D02E36 /* HTTPServer.swift */; };
152EF3942283457C001E1269 /* TestNSSortDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152EF3932283457B001E1269 /* TestNSSortDescriptor.swift */; };
153CC8352215E00200BFE8F3 /* ScannerAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 153CC8322214C3D100BFE8F3 /* ScannerAPI.swift */; };
153E951120111DC500F250BE /* CFKnownLocations.h in Headers */ = {isa = PBXBuildFile; fileRef = 153E950F20111DC500F250BE /* CFKnownLocations.h */; settings = {ATTRIBUTES = (Private, ); }; };
153E951220111DC500F250BE /* CFKnownLocations.c in Sources */ = {isa = PBXBuildFile; fileRef = 153E951020111DC500F250BE /* CFKnownLocations.c */; };
Expand Down Expand Up @@ -556,6 +557,7 @@
03B6F5831F15F339004F25AF /* TestURLProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestURLProtocol.swift; sourceTree = "<group>"; };
1513A8422044893F00539722 /* FileManager_XDG.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManager_XDG.swift; sourceTree = "<group>"; };
1520469A1D8AEABE00D02E36 /* HTTPServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPServer.swift; sourceTree = "<group>"; };
152EF3932283457B001E1269 /* TestNSSortDescriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSSortDescriptor.swift; sourceTree = "<group>"; };
153CC8322214C3D100BFE8F3 /* ScannerAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannerAPI.swift; sourceTree = "<group>"; };
153E950F20111DC500F250BE /* CFKnownLocations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CFKnownLocations.h; sourceTree = "<group>"; };
153E951020111DC500F250BE /* CFKnownLocations.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = CFKnownLocations.c; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1641,6 +1643,7 @@
EA66F6401BF1619600136161 /* TestPropertyListSerialization.swift */,
E876A73D1C1180E000F279EC /* TestNSRange.swift */,
5B0C6C211C1E07E600705A0E /* TestNSRegularExpression.swift */,
152EF3932283457B001E1269 /* TestNSSortDescriptor.swift */,
61E0117B1C1B554D000037DD /* TestRunLoop.swift */,
844DC3321C17584F005611F9 /* TestScanner.swift */,
EA66F6411BF1619600136161 /* TestNSSet.swift */,
Expand Down Expand Up @@ -2624,6 +2627,7 @@
B90C57BB1EEEEA5A005208AE /* TestFileManager.swift in Sources */,
A058C2021E529CF100B07AA1 /* TestMassFormatter.swift in Sources */,
5B13B3381C582D4C00651CE2 /* TestNotificationQueue.swift in Sources */,
152EF3942283457C001E1269 /* TestNSSortDescriptor.swift in Sources */,
CC5249C01D341D23007CB54D /* TestUnitConverter.swift in Sources */,
5B13B3331C582D4C00651CE2 /* TestJSONSerialization.swift in Sources */,
5B13B33C1C582D4C00651CE2 /* TestNSOrderedSet.swift in Sources */,
Expand Down
28 changes: 28 additions & 0 deletions Foundation/NSArray.swift
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,12 @@ open class NSArray : NSObject, NSCopying, NSMutableCopying, NSSecureCoding, NSCo
override open var _cfTypeID: CFTypeID {
return CFArrayGetTypeID()
}

open func sortedArray(using sortDescriptors: [NSSortDescriptor]) -> [Any] {
let copied = mutableCopy() as! NSMutableArray
copied.sort(using: sortDescriptors)
return copied._swiftObject
}
}

extension NSArray : _CFBridgeable, _SwiftBridgeable {
Expand Down Expand Up @@ -939,6 +945,28 @@ open class NSMutableArray : NSArray {
open func sort(options opts: NSSortOptions = [], usingComparator cmptr: Comparator) {
self.setArray(self.sortedArray(options: opts, usingComparator: cmptr))
}

open func sort(using sortDescriptors: [NSSortDescriptor]) {
var descriptors = sortDescriptors._nsObject
CFArraySortValues(_cfMutableObject, CFRangeMake(0, count), { (lhsPointer, rhsPointer, context) -> CFComparisonResult in
let descriptors = context!.assumingMemoryBound(to: NSArray.self).pointee._swiftObject

for item in descriptors {
let descriptor = item as! NSSortDescriptor
let result =
descriptor.compare(__SwiftValue.fetch(Unmanaged<AnyObject>.fromOpaque(lhsPointer!).takeUnretainedValue())!,
to: __SwiftValue.fetch(Unmanaged<AnyObject>.fromOpaque(rhsPointer!).takeUnretainedValue())!)

if result == .orderedAscending {
return kCFCompareLessThan
} else if result == .orderedDescending {
return kCFCompareGreaterThan
}
}

return kCFCompareEqualTo
}, &descriptors)
}
}

extension NSArray : Sequence {
Expand Down
9 changes: 7 additions & 2 deletions Foundation/NSCFArray.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ internal func _CFSwiftArrayRemoveAllValues(_ array: AnyObject) {
}

internal func _CFSwiftArrayReplaceValues(_ array: AnyObject, _ range: CFRange, _ newValues: UnsafeMutablePointer<Unmanaged<AnyObject>>, _ newCount: CFIndex) {
NSUnimplemented()
// (array as! NSMutableArray).replaceObjectsInRange(NSRange(location: range.location, length: range.length), withObjectsFrom: newValues.array(newCount))
let buffer: UnsafeBufferPointer<Unmanaged<AnyObject>> = UnsafeBufferPointer(start: newValues, count: newCount)
let replacements = Array(buffer).map { $0.takeUnretainedValue() }
(array as! NSMutableArray).replaceObjects(in: NSRange(location: range.location, length: range.length), withObjectsFrom: replacements)
}

internal func _CFSwiftArrayIsSubclassOfNSMutableArray(_ array: AnyObject) -> _DarwinCompatibleBoolean {
return array is NSMutableArray ? true : false
}
7 changes: 7 additions & 0 deletions Foundation/NSDate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -427,3 +427,10 @@ extension NSDateInterval : _StructTypeBridgeable {
return DateInterval._unconditionallyBridgeFromObjectiveC(self)
}
}

extension NSDateInterval : _SwiftBridgeable {
var _swiftObject: DateInterval {
return _bridgeToSwift()
}
}

7 changes: 7 additions & 0 deletions Foundation/NSIndexPath.swift
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,10 @@ extension NSIndexPath : _StructTypeBridgeable {
return IndexPath._unconditionallyBridgeFromObjectiveC(self)
}
}

extension NSIndexPath : _SwiftBridgeable {
var _swiftObject: IndexPath {
return _bridgeToSwift()
}
}

12 changes: 10 additions & 2 deletions Foundation/NSOrderedSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ open class NSOrderedSet: NSObject, NSCopying, NSMutableCopying, NSSecureCoding,
// being made.
public var array: [Any] {
if type(of: self) === NSOrderedSet.self || type(of: self) === NSMutableOrderedSet.self {
return _orderedStorage._storage
return _orderedStorage._swiftObject
} else {
var result: [Any] = []
result.reserveCapacity(self.count)
Expand All @@ -268,7 +268,7 @@ open class NSOrderedSet: NSObject, NSCopying, NSMutableCopying, NSSecureCoding,

public var set: Set<AnyHashable> {
if type(of: self) === NSOrderedSet.self || type(of: self) === NSMutableOrderedSet.self {
return _storage._storage
return _storage._swiftObject
} else {
var result: Set<AnyHashable> = []
result.reserveCapacity(self.count)
Expand Down Expand Up @@ -392,6 +392,10 @@ open class NSOrderedSet: NSObject, NSCopying, NSMutableCopying, NSSecureCoding,
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)
}
}


Expand Down Expand Up @@ -664,6 +668,10 @@ open class NSMutableOrderedSet: NSOrderedSet {
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)
}
}


Expand Down
4 changes: 4 additions & 0 deletions Foundation/NSSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,10 @@ open class NSSet : NSObject, NSCopying, NSMutableCopying, NSSecureCoding, NSCodi
}
return result
}

open func sortedArray(using sortDescriptors: [NSSortDescriptor]) -> [Any] {
return allObjects._nsObject.sortedArray(using: sortDescriptors)
}
}

extension NSSet : _CFBridgeable, _SwiftBridgeable {
Expand Down
136 changes: 91 additions & 45 deletions Foundation/NSSortDescriptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,72 +7,118 @@
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//

import CoreFoundation

open class NSSortDescriptor: NSObject, NSSecureCoding, NSCopying {

public required init?(coder aDecoder: NSCoder) {
NSUnimplemented()
}

open func encode(with aCoder: NSCoder) {
NSUnimplemented()
}

static public var supportsSecureCoding: Bool {
return true
}

// In swift-corelibs-foundation, key-value coding is not available. Since encoding and decoding a NSSortDescriptor requires interpreting key paths, NSSortDescriptor does not conform to NSCoding or NSSecureCoding in swift-corelibs-foundation only.
open class NSSortDescriptor: NSObject, NSCopying {
open override func copy() -> Any {
return copy(with: nil)
}

open func copy(with zone: NSZone? = nil) -> Any {
NSUnimplemented()
return self
}

// keys may be key paths
public init(key: String?, ascending: Bool) { NSUnimplemented() }
@available(*, unavailable, message: "Key-value coding is not available in swift-corelibs-foundation. Use Swift key paths instead with init(keyPath:ascending:) or init(keyPath:ascending:comparator:)", renamed: "init(keyPath:ascending:)")
public init(key: String?, ascending: Bool) { NSUnsupported() }

open var key: String? { NSUnimplemented() }
open var ascending: Bool { NSUnimplemented() }
public var keyPath: AnyKeyPath? { NSUnimplemented() }
@available(*, unavailable, message: "Key-value coding is not available in swift-corelibs-foundation. Use Swift key paths instead with init(keyPath:ascending:) or init(keyPath:ascending:comparator:)", renamed: "init(keyPath:ascending:)")
public init(key: String?, ascending: Bool, comparator cmptr: Comparator) { NSUnsupported() }

open func allowEvaluation() { NSUnimplemented() } // Force a sort descriptor which was securely decoded to allow evaluation

public init(key: String?, ascending: Bool, comparator cmptr: Comparator) { NSUnimplemented() }
public convenience init<Root, Value>(keyPath: KeyPath<Root, Value>, ascending: Bool) { NSUnimplemented() }
public convenience init<Root, Value>(keyPath: KeyPath<Root, Value>, ascending: Bool, comparator cmptr: @escaping Comparator) { NSUnimplemented() }
@available(*, unavailable, message: "Key-value coding is not available in swift-corelibs-foundation. Use .keyPath instead.", renamed: "keyPath")
open var key: String? { NSUnsupported() }

open var comparator: Comparator { NSUnimplemented() }
@available(*, unavailable, message: "Sort descriptors cannot be decoded from archives in swift-corelibs-foundation.")
open func allowEvaluation() {}

open func compare(_ object1: Any, to object2: Any) -> ComparisonResult { NSUnimplemented() }// primitive - override this method if you want to perform comparisons differently (not key based for example)
open var reversedSortDescriptor: Any { NSUnimplemented() } // primitive - override this method to return a sort descriptor instance with reversed sort order
}

extension NSSet {
// MARK: Available parts.

public init<Root, Value: Comparable>(keyPath: KeyPath<Root, Value>, ascending: Bool) {
self.keyPath = keyPath
self.ascending = ascending
self.lens = { ($0 as! Root)[keyPath: keyPath] }
self.comparator = { (a, b) -> ComparisonResult in
let valueA = a as! Value
let valueB = b as! Value

if valueA < valueB {
return .orderedAscending
} else if valueB < valueA {
return .orderedDescending
} else {
return .orderedSame
}
}
self.reversedSortDescriptorProducer = { return NSSortDescriptor(keyPath: keyPath, ascending: !ascending) }
}

public init<Root, Value>(keyPath: KeyPath<Root, Value>, ascending: Bool, comparator cmptr: @escaping Comparator) {
self.keyPath = keyPath
self.ascending = ascending
self.lens = { ($0 as! Root)[keyPath: keyPath] }
self.comparator = cmptr
self.reversedSortDescriptorProducer = { return NSSortDescriptor(keyPath: keyPath, ascending: !ascending, comparator: cmptr) }
}

private let lens: (Any) -> Any
private let reversedSortDescriptorProducer: () -> NSSortDescriptor

public func sortedArray(using sortDescriptors: [NSSortDescriptor]) -> [Any] { NSUnimplemented() }// returns a new array by sorting the objects of the receiver
open private(set) var ascending: Bool
open private(set) var keyPath: AnyKeyPath
open private(set) var comparator: Comparator

// primitive - override this method if you want to perform comparisons differently (not key based for example)
open func compare(_ object1: Any, to object2: Any) -> ComparisonResult {
let lhs = lens(object1)
let rhs = lens(object2)
let result = comparator(lhs, rhs)

let actualResult: ComparisonResult

if ascending {
actualResult = result
} else {
switch result {
case .orderedAscending: actualResult = .orderedDescending
case .orderedDescending: actualResult = .orderedAscending
case .orderedSame: actualResult = .orderedSame
}
}

return actualResult
}
open var reversedSortDescriptor: Any {
return reversedSortDescriptorProducer()
}
}

extension NSArray {

public func sortedArray(using sortDescriptors: [NSSortDescriptor]) -> [Any] { NSUnimplemented() }// returns a new array by sorting the objects of the receiver
extension NSNumber: Comparable {
public static func < (lhs: NSNumber, rhs: NSNumber) -> Bool {
return lhs.compare(rhs) == .orderedAscending
}
}

extension NSMutableArray {

public func sort(using sortDescriptors: [NSSortDescriptor]) { NSUnimplemented() } // sorts the array itself
extension NSString: Comparable {
public static func < (lhs: NSString, rhs: NSString) -> Bool {
return lhs.compare(rhs._swiftObject) == .orderedAscending
}
}

extension NSDateInterval: Comparable {
public static func < (lhs: NSDateInterval, rhs: NSDateInterval) -> Bool {
return lhs.compare(rhs._swiftObject) == .orderedAscending
}
}

extension NSOrderedSet {

// returns a new array by sorting the objects of the receiver
public func sortedArray(using sortDescriptors: [NSSortDescriptor]) -> [Any] { NSUnimplemented() }
extension NSDate: Comparable {
public static func < (lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.compare(rhs._swiftObject) == .orderedAscending
}
}

extension NSMutableOrderedSet {

// sorts the ordered set itself
public func sort(using sortDescriptors: [NSSortDescriptor]) { NSUnimplemented() }
extension NSIndexPath: Comparable {
public static func < (lhs: NSIndexPath, rhs: NSIndexPath) -> Bool {
return lhs.compare(rhs._swiftObject) == .orderedAscending
}
}
1 change: 1 addition & 0 deletions Foundation/NSSwiftRuntime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ internal func __CFInitializeSwift() {
__CFSwiftBridge.NSArray.count = _CFSwiftArrayGetCount
__CFSwiftBridge.NSArray.objectAtIndex = _CFSwiftArrayGetValueAtIndex
__CFSwiftBridge.NSArray.getObjects = _CFSwiftArrayGetValues
__CFSwiftBridge.NSArray.isSubclassOfNSMutableArray = _CFSwiftArrayIsSubclassOfNSMutableArray

__CFSwiftBridge.NSMutableArray.addObject = _CFSwiftArrayAppendValue
__CFSwiftBridge.NSMutableArray.setObject = _CFSwiftArraySetValueAtIndex
Expand Down