Skip to content

Commit bb81b24

Browse files
authored
Merge pull request #20918 from lorentey/dictionary-modify-layering
[stdlib] Refactor Dictionary.subscript._modify for better layering
2 parents 688db2b + d32fd28 commit bb81b24

File tree

3 files changed

+64
-38
lines changed

3 files changed

+64
-38
lines changed

stdlib/public/core/Dictionary.swift

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -794,44 +794,7 @@ extension Dictionary {
794794
}
795795
}
796796
_modify {
797-
// FIXME: This code should be moved to _variant, with Dictionary.subscript
798-
// yielding `&_variant[key]`.
799-
800-
let (bucket, found) = _variant.mutatingFind(key)
801-
802-
// FIXME: Mark this entry as being modified in hash table metadata
803-
// so that lldb can recognize it's not valid.
804-
805-
// Move the old value (if any) out of storage, wrapping it into an
806-
// optional before yielding it.
807-
let native = _variant.asNative
808-
if found {
809-
var value: Value? = (native._values + bucket.offset).move()
810-
yield &value
811-
if let value = value {
812-
// **Mutation**
813-
//
814-
// Initialize storage to new value.
815-
(native._values + bucket.offset).initialize(to: value)
816-
} else {
817-
// **Removal**
818-
//
819-
// We've already deinitialized the value; deinitialize the key too and
820-
// register the removal.
821-
(native._keys + bucket.offset).deinitialize(count: 1)
822-
native._delete(at: bucket)
823-
}
824-
} else {
825-
var value: Value? = nil
826-
yield &value
827-
if let value = value {
828-
// **Insertion**
829-
//
830-
// Insert the new entry at the correct place. Note that
831-
// `mutatingFind` already ensured that we have enough capacity.
832-
native._insert(at: bucket, key: key, value: value)
833-
}
834-
}
797+
yield &_variant[key]
835798
_fixLifetime(self)
836799
}
837800
}

stdlib/public/core/DictionaryVariant.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,31 @@ extension Dictionary._Variant: _DictionaryBuffer {
278278
}
279279
}
280280

281+
extension Dictionary._Variant {
282+
@inlinable
283+
internal subscript(key: Key) -> Value? {
284+
@inline(__always)
285+
get {
286+
return lookup(key)
287+
}
288+
@inline(__always)
289+
_modify {
290+
#if _runtime(_ObjC)
291+
guard isNative else {
292+
let cocoa = asCocoa
293+
var native = _NativeDictionary<Key, Value>(
294+
cocoa, capacity: cocoa.count + 1)
295+
self = .init(native: native)
296+
yield &native[key, isUnique: true]
297+
return
298+
}
299+
#endif
300+
let isUnique = isUniquelyReferenced()
301+
yield &asNative[key, isUnique: isUnique]
302+
}
303+
}
304+
}
305+
281306
extension Dictionary._Variant {
282307
/// Same as find(_:), except assume a corresponding key/value pair will be
283308
/// inserted if it doesn't already exist, and mutated if it does exist. When

stdlib/public/core/NativeDictionary.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,44 @@ extension _NativeDictionary: _DictionaryBuffer {
387387
}
388388
}
389389

390+
extension _NativeDictionary {
391+
@inlinable
392+
subscript(key: Key, isUnique isUnique: Bool) -> Value? {
393+
@inline(__always)
394+
get {
395+
// Dummy definition; don't use.
396+
return lookup(key)
397+
}
398+
@inline(__always)
399+
_modify {
400+
let (bucket, found) = mutatingFind(key, isUnique: isUnique)
401+
if found {
402+
// Move the old value out of storage, wrapping it into an optional
403+
// before yielding it.
404+
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)
414+
}
415+
} else {
416+
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)
422+
}
423+
}
424+
}
425+
}
426+
}
427+
390428
// This function has a highly visible name to make it stand out in stack traces.
391429
@usableFromInline
392430
@inline(never)

0 commit comments

Comments
 (0)