@@ -229,6 +229,11 @@ internal protocol _HashStorage {
229
229
@discardableResult
230
230
mutating func updateValue(_ value: Value, forKey key: Key) -> Value?
231
231
232
+ @discardableResult
233
+ mutating func insert(
234
+ _ value: Value, forKey key: Key
235
+ ) -> (inserted: Bool, memberAfterInsert: Value)
236
+
232
237
@discardableResult
233
238
mutating func remove(at index: Index) -> SequenceElement
234
239
@@ -577,12 +582,7 @@ public struct Set<Element : Hashable> :
577
582
public mutating func insert(
578
583
_ newMember: Element
579
584
) -> (inserted: Bool, memberAfterInsert: Element) {
580
- // FIXME: optimize this to do just one lookup
581
- if let i = index(of: newMember) {
582
- return (inserted: false, memberAfterInsert: self[i])
583
- }
584
- _variantStorage.updateValue(newMember, forKey: newMember)
585
- return (inserted: true, memberAfterInsert: newMember)
585
+ return _variantStorage.insert(newMember, forKey: newMember)
586
586
}
587
587
588
588
/// Inserts `newMember` unconditionally.
@@ -2730,6 +2730,14 @@ struct _Native${Self}Storage<${TypeParametersDecl}> :
2730
2730
"don't call mutating methods on _Native${Self}Storage")
2731
2731
}
2732
2732
2733
+ @discardableResult
2734
+ internal mutating func insert(
2735
+ _ value: Value, forKey key: Key
2736
+ ) -> (inserted: Bool, memberAfterInsert: Value) {
2737
+ _sanityCheckFailure(
2738
+ "don't call mutating methods on _Native${Self}Storage")
2739
+ }
2740
+
2733
2741
@discardableResult
2734
2742
internal mutating func remove(at index: Index) -> SequenceElement {
2735
2743
_sanityCheckFailure(
@@ -3421,6 +3429,13 @@ internal struct _Cocoa${Self}Storage : _HashStorage {
3421
3429
_sanityCheckFailure("cannot mutate NS${Self}")
3422
3430
}
3423
3431
3432
+ @discardableResult
3433
+ internal mutating func insert(
3434
+ _ value: Value, forKey key: Key
3435
+ ) -> (inserted: Bool, memberAfterInsert: Value) {
3436
+ _sanityCheckFailure("cannot mutate NS${Self}")
3437
+ }
3438
+
3424
3439
@discardableResult
3425
3440
internal mutating func remove(at index: Index) -> SequenceElement {
3426
3441
_sanityCheckFailure("cannot mutate NS${Self}")
@@ -3843,6 +3858,61 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorage {
3843
3858
}
3844
3859
}
3845
3860
3861
+ internal mutating func nativeInsert(
3862
+ _ value: Value, forKey key: Key
3863
+ ) -> (inserted: Bool, memberAfterInsert: Value) {
3864
+ var (i, found) = asNative._find(key, startBucket: asNative._bucket(key))
3865
+
3866
+ if found {
3867
+ %if Self == 'Set':
3868
+ return (inserted: false, memberAfterInsert: asNative.key(at: i.offset))
3869
+ %elif Self == 'Dictionary':
3870
+ return (inserted: false, memberAfterInsert: asNative.value(at: i.offset))
3871
+ %end
3872
+ }
3873
+
3874
+ let minCapacity = NativeStorage.minimumCapacity(
3875
+ minimumCount: asNative.count + 1,
3876
+ maxLoadFactorInverse: asNative.maxLoadFactorInverse)
3877
+
3878
+ let (_, capacityChanged) = ensureUniqueNativeStorage(minCapacity)
3879
+ if capacityChanged {
3880
+ i = asNative._find(key, startBucket: asNative._bucket(key)).pos
3881
+ }
3882
+
3883
+ %if Self == 'Set':
3884
+ asNative.initializeKey(key, at: i.offset)
3885
+ asNative.count += 1
3886
+ %elif Self == 'Dictionary':
3887
+ asNative.initializeKey(key, value: value, at: i.offset)
3888
+ asNative.count += 1
3889
+ %end
3890
+
3891
+ return (inserted: true, memberAfterInsert: value)
3892
+ }
3893
+
3894
+ @discardableResult
3895
+ internal mutating func insert(
3896
+ _ value: Value, forKey key: Key
3897
+ ) -> (inserted: Bool, memberAfterInsert: Value) {
3898
+
3899
+ if _fastPath(guaranteedNative) {
3900
+ return nativeInsert(value, forKey: key)
3901
+ }
3902
+
3903
+ switch self {
3904
+ case .native:
3905
+ return nativeInsert(value, forKey: key)
3906
+ case .cocoa(let cocoaStorage):
3907
+ #if _runtime(_ObjC)
3908
+ migrateDataToNativeStorage(cocoaStorage)
3909
+ return nativeInsert(value, forKey: key)
3910
+ #else
3911
+ _sanityCheckFailure("internal error: unexpected cocoa ${Self}")
3912
+ #endif
3913
+ }
3914
+ }
3915
+
3846
3916
/// - parameter idealBucket: The ideal bucket for the element being deleted.
3847
3917
/// - parameter offset: The offset of the element that will be deleted.
3848
3918
/// Precondition: there should be an initialized entry at offset.
0 commit comments