Skip to content

Commit

Permalink
Merge pull request #2232 from millenomi/nsorderedset-nscoding
Browse files Browse the repository at this point in the history
  • Loading branch information
swift-ci committed May 13, 2019
2 parents 155f1ce + aa3e6e1 commit 4c0fef0
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 55 deletions.
87 changes: 71 additions & 16 deletions Foundation/NSOrderedSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,8 @@ open class NSOrderedSet: NSObject, NSCopying, NSMutableCopying, NSSecureCoding,
}

public required convenience init?(coder aDecoder: NSCoder) {
guard aDecoder.allowsKeyedCoding else {
preconditionFailure("Unkeyed coding is unsupported.")
}
var idx = 0
var objects : [AnyObject] = []
while aDecoder.containsValue(forKey: ("NS.object.\(idx)")) {
guard let object = aDecoder.decodeObject(forKey: "NS.object.\(idx)") else {
return nil
}
objects.append(object as! NSObject)
idx += 1
}
self.init(array: objects)
// 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 {
Expand Down Expand Up @@ -339,7 +328,7 @@ open class NSOrderedSet: NSObject, NSCopying, NSMutableCopying, NSSecureCoding,
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])
}
Expand Down Expand Up @@ -370,7 +359,7 @@ open class NSOrderedSet: NSObject, NSCopying, NSMutableCopying, NSSecureCoding,
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

Expand Down Expand Up @@ -470,7 +459,10 @@ open class NSMutableOrderedSet: NSOrderedSet {
_orderedStorage = _mutableOrderedStorage
}

public required init?(coder aDecoder: NSCoder) { NSUnimplemented() }
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 {
Expand Down Expand Up @@ -672,6 +664,69 @@ open class NSMutableOrderedSet: NSOrderedSet {
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)
}
}


Expand Down
8 changes: 5 additions & 3 deletions Foundation/NSSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,19 @@ open class NSSet : NSObject, NSCopying, NSMutableCopying, NSSecureCoding, NSCodi
self.init(array: [object])
}

internal class func _objects(from aDecoder: NSCoder) -> [NSObject] {
internal class func _objects(from aDecoder: NSCoder, allowDecodingNonindexedArrayKey: Bool = true) -> [NSObject] {
guard aDecoder.allowsKeyedCoding else {
preconditionFailure("Unkeyed coding is unsupported.")
}
if type(of: aDecoder) == NSKeyedUnarchiver.self || aDecoder.containsValue(forKey: "NS.objects") {
if (allowDecodingNonindexedArrayKey && type(of: aDecoder) == NSKeyedUnarchiver.self) || aDecoder.containsValue(forKey: "NS.objects") {
let objects = aDecoder._decodeArrayOfObjectsForKey("NS.objects")
return objects as! [NSObject]
} else {
var objects: [NSObject] = []
var count = 0
while let object = aDecoder.decodeObject(forKey: "NS.object.\(count)") {
var key: String { return "NS.object.\(count)" }
while aDecoder.containsValue(forKey: key) {
let object = aDecoder.decodeObject(forKey: key)
objects.append(object as! NSObject)
count += 1
}
Expand Down
24 changes: 24 additions & 0 deletions TestFoundation/FixtureValues.swift
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,26 @@ enum Fixtures {
return NSCharacterSet.alphanumerics as NSCharacterSet
}

// ===== NSOrderedSet, NSMutableOrderedSet =====

static let orderedSetOfNumbers = TypedFixture<NSOrderedSet>("NSOrderedSet-Numbers") {
let numbers = [1, 2, 3, 4, 5].map { NSNumber(value: $0) }
return NSOrderedSet(array: numbers)
}

static let orderedSetEmpty = TypedFixture<NSOrderedSet>("NSOrderedSet-Empty") {
return NSOrderedSet()
}

static let mutableOrderedSetOfNumbers = TypedFixture<NSMutableOrderedSet>("NSMutableOrderedSet-Numbers") {
let numbers = [1, 2, 3, 4, 5].map { NSNumber(value: $0) }
return NSMutableOrderedSet(array: numbers)
}

static let mutableOrderedSetEmpty = TypedFixture<NSMutableOrderedSet>("NSMutableOrderedSet-Empty") {
return NSMutableOrderedSet()
}

// ===== Fixture list =====

static let _listOfAllFixtures: [AnyFixture] = [
Expand Down Expand Up @@ -273,6 +293,10 @@ enum Fixtures {
AnyFixture(Fixtures.characterSetString),
AnyFixture(Fixtures.characterSetBitmap),
AnyFixture(Fixtures.characterSetBuiltin),
AnyFixture(Fixtures.orderedSetOfNumbers),
AnyFixture(Fixtures.orderedSetEmpty),
AnyFixture(Fixtures.mutableOrderedSetOfNumbers),
AnyFixture(Fixtures.mutableOrderedSetEmpty),
]

// This ensures that we do not have fixtures with duplicate identifiers:
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
101 changes: 65 additions & 36 deletions TestFoundation/TestNSOrderedSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,6 @@

class TestNSOrderedSet : XCTestCase {

static var allTests: [(String, (TestNSOrderedSet) -> () throws -> Void)] {
return [
("test_BasicConstruction", test_BasicConstruction),
("test_Enumeration", test_Enumeration),
("test_Uniqueness", test_Uniqueness),
("test_reversedEnumeration", test_reversedEnumeration),
("test_reversedOrderedSet", test_reversedOrderedSet),
("test_reversedEmpty", test_reversedEmpty),
("test_ObjectAtIndex", test_ObjectAtIndex),
("test_ObjectsAtIndexes", test_ObjectsAtIndexes),
("test_FirstAndLastObjects", test_FirstAndLastObjects),
("test_AddObject", test_AddObject),
("test_AddObjects", test_AddObjects),
("test_RemoveAllObjects", test_RemoveAllObjects),
("test_RemoveObject", test_RemoveObject),
("test_RemoveObjectAtIndex", test_RemoveObjectAtIndex),
("test_IsEqualToOrderedSet", test_IsEqualToOrderedSet),
("test_Subsets", test_Subsets),
("test_ReplaceObject", test_ReplaceObject),
("test_ExchangeObjects", test_ExchangeObjects),
("test_MoveObjects", test_MoveObjects),
("test_InsertObjects", test_InsertObjects),
("test_Insert", test_Insert),
("test_SetObjectAtIndex", test_SetObjectAtIndex),
("test_RemoveObjectsInRange", test_RemoveObjectsInRange),
("test_ReplaceObjectsAtIndexes", test_ReplaceObjectsAtIndexes),
("test_Intersection", test_Intersection),
("test_Subtraction", test_Subtraction),
("test_Union", test_Union),
("test_Initializers", test_Initializers),
("test_Sorting", test_Sorting),
("test_reversedEnumerationMutable", test_reversedEnumerationMutable),
("test_reversedOrderedSetMutable", test_reversedOrderedSetMutable),
]
}

func test_BasicConstruction() {
let set = NSOrderedSet()
let set2 = NSOrderedSet(array: ["foo", "bar"])
Expand Down Expand Up @@ -513,4 +477,69 @@ class TestNSOrderedSet : XCTestCase {
XCTAssertEqual(work.lastObject as? String, krow.firstObject as? String)
}

let fixtures = [
Fixtures.orderedSetEmpty,
Fixtures.orderedSetOfNumbers
]

let mutableFixtures = [
Fixtures.mutableOrderedSetEmpty,
Fixtures.mutableOrderedSetOfNumbers
]

func test_codingRoundtrip() throws {
for fixture in fixtures {
try fixture.assertValueRoundtripsInCoder()
}
for fixture in mutableFixtures {
try fixture.assertValueRoundtripsInCoder()
}
}

func test_loadedValuesMatch() throws {
for fixture in fixtures {
try fixture.assertLoadedValuesMatch()
}
for fixture in mutableFixtures {
try fixture.assertLoadedValuesMatch()
}
}

static var allTests: [(String, (TestNSOrderedSet) -> () throws -> Void)] {
return [
("test_BasicConstruction", test_BasicConstruction),
("test_Enumeration", test_Enumeration),
("test_Uniqueness", test_Uniqueness),
("test_reversedEnumeration", test_reversedEnumeration),
("test_reversedOrderedSet", test_reversedOrderedSet),
("test_reversedEmpty", test_reversedEmpty),
("test_ObjectAtIndex", test_ObjectAtIndex),
("test_ObjectsAtIndexes", test_ObjectsAtIndexes),
("test_FirstAndLastObjects", test_FirstAndLastObjects),
("test_AddObject", test_AddObject),
("test_AddObjects", test_AddObjects),
("test_RemoveAllObjects", test_RemoveAllObjects),
("test_RemoveObject", test_RemoveObject),
("test_RemoveObjectAtIndex", test_RemoveObjectAtIndex),
("test_IsEqualToOrderedSet", test_IsEqualToOrderedSet),
("test_Subsets", test_Subsets),
("test_ReplaceObject", test_ReplaceObject),
("test_ExchangeObjects", test_ExchangeObjects),
("test_MoveObjects", test_MoveObjects),
("test_InsertObjects", test_InsertObjects),
("test_Insert", test_Insert),
("test_SetObjectAtIndex", test_SetObjectAtIndex),
("test_RemoveObjectsInRange", test_RemoveObjectsInRange),
("test_ReplaceObjectsAtIndexes", test_ReplaceObjectsAtIndexes),
("test_Intersection", test_Intersection),
("test_Subtraction", test_Subtraction),
("test_Union", test_Union),
("test_Initializers", test_Initializers),
("test_Sorting", test_Sorting),
("test_reversedEnumerationMutable", test_reversedEnumerationMutable),
("test_reversedOrderedSetMutable", test_reversedOrderedSetMutable),
("test_codingRoundtrip", test_codingRoundtrip),
("test_loadedValuesMatch", test_loadedValuesMatch),
]
}
}

0 comments on commit 4c0fef0

Please sign in to comment.