Skip to content

Commit b773515

Browse files
authored
Merge pull request swiftlang#21045 from lorentey/modify-vs-throw
[stdlib] Dictionary: Support throwing yields in _modify accessors
2 parents 6f67481 + ce96f1e commit b773515

File tree

6 files changed

+276
-38
lines changed

6 files changed

+276
-38
lines changed

stdlib/public/core/Dictionary.swift

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -794,8 +794,8 @@ extension Dictionary {
794794
}
795795
}
796796
_modify {
797+
defer { _fixLifetime(self) }
797798
yield &_variant[key]
798-
_fixLifetime(self)
799799
}
800800
}
801801
}
@@ -898,8 +898,8 @@ extension Dictionary {
898898
native._insert(at: bucket, key: key, value: value)
899899
}
900900
let address = native._values + bucket.offset
901+
defer { _fixLifetime(self) }
901902
yield &address.pointee
902-
_fixLifetime(self)
903903
}
904904
}
905905

@@ -1272,14 +1272,10 @@ extension Dictionary {
12721272
return Values(_dictionary: self)
12731273
}
12741274
_modify {
1275-
var values: Values
1276-
do {
1277-
var temp = _Variant(dummy: ())
1278-
swap(&temp, &_variant)
1279-
values = Values(_variant: temp)
1280-
}
1275+
var values = Values(_variant: _Variant(dummy: ()))
1276+
swap(&values._variant, &_variant)
1277+
defer { self._variant = values._variant }
12811278
yield &values
1282-
self._variant = values._variant
12831279
}
12841280
}
12851281

@@ -1462,8 +1458,8 @@ extension Dictionary {
14621458
let native = _variant.ensureUniqueNative()
14631459
let bucket = native.validatedBucket(for: position)
14641460
let address = native._values + bucket.offset
1461+
defer { _fixLifetime(self) }
14651462
yield &address.pointee
1466-
_fixLifetime(self)
14671463
}
14681464
}
14691465

@@ -1846,8 +1842,8 @@ extension Dictionary.Index {
18461842
}
18471843
let dummy = _HashTable.Index(bucket: _HashTable.Bucket(offset: 0), age: 0)
18481844
_variant = .native(dummy)
1845+
defer { _variant = .cocoa(cocoa) }
18491846
yield &cocoa
1850-
_variant = .cocoa(cocoa)
18511847
}
18521848
}
18531849
#endif

stdlib/public/core/DictionaryVariant.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ extension Dictionary._Variant {
9595
_modify {
9696
var native = _NativeDictionary<Key, Value>(object.unflaggedNativeInstance)
9797
self = .init(dummy: ())
98+
defer { object = .init(native: native._storage) }
9899
yield &native
99-
object = .init(native: native._storage)
100100
}
101101
}
102102

stdlib/public/core/NativeDictionary.swift

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -402,24 +402,32 @@ extension _NativeDictionary {
402402
// Move the old value out of storage, wrapping it into an optional
403403
// before yielding it.
404404
var value: Value? = (_values + bucket.offset).move()
405-
yield &value
406-
if let value = value {
407-
// **Mutation.** Initialize storage to new value.
408-
(_values + bucket.offset).initialize(to: value)
409-
} else {
410-
// **Removal.** We've already deinitialized the value; deinitialize
411-
// the key too and register the removal.
412-
(_keys + bucket.offset).deinitialize(count: 1)
413-
_delete(at: bucket)
405+
defer {
406+
// This is in a defer block because yield might throw, and we need to
407+
// preserve Dictionary's storage invariants when that happens.
408+
if let value = value {
409+
// **Mutation.** Initialize storage to new value.
410+
(_values + bucket.offset).initialize(to: value)
411+
} else {
412+
// **Removal.** We've already deinitialized the value; deinitialize
413+
// the key too and register the removal.
414+
(_keys + bucket.offset).deinitialize(count: 1)
415+
_delete(at: bucket)
416+
}
414417
}
418+
yield &value
415419
} else {
416420
var value: Value? = nil
417-
yield &value
418-
if let value = value {
419-
// **Insertion.** Insert the new entry at the correct place. Note
420-
// that `mutatingFind` already ensured that we have enough capacity.
421-
_insert(at: bucket, key: key, value: value)
421+
defer {
422+
// This is in a defer block because yield might throw, and we need to
423+
// preserve Dictionary invariants when that happens.
424+
if let value = value {
425+
// **Insertion.** Insert the new entry at the correct place. Note
426+
// that `mutatingFind` already ensured that we have enough capacity.
427+
_insert(at: bucket, key: key, value: value)
428+
}
422429
}
430+
yield &value
423431
}
424432
}
425433
}

stdlib/public/core/Set.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1367,8 +1367,8 @@ extension Set.Index {
13671367
}
13681368
let dummy = _HashTable.Index(bucket: _HashTable.Bucket(offset: 0), age: 0)
13691369
_variant = .native(dummy)
1370+
defer { _variant = .cocoa(cocoa) }
13701371
yield &cocoa
1371-
_variant = .cocoa(cocoa)
13721372
}
13731373
}
13741374
#endif

stdlib/public/core/SetVariant.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,12 @@ extension Set._Variant {
9292
_modify {
9393
var native = _NativeSet<Element>(object.unflaggedNativeInstance)
9494
self = .init(dummy: ())
95+
defer {
96+
// This is in a defer block because yield might throw, and we need to
97+
// preserve Set's storage invariants when that happens.
98+
object = .init(native: native._storage)
99+
}
95100
yield &native
96-
object = .init(native: native._storage)
97101
}
98102
}
99103

0 commit comments

Comments
 (0)