Skip to content

Commit d799578

Browse files
authored
Merge pull request swiftlang#19574 from lorentey/buckets
[stdlib] Rename _HashTable.Index in preparation of upcoming index validation enhancements
2 parents 61b96d0 + 231fbc6 commit d799578

12 files changed

+492
-502
lines changed

stdlib/public/core/Dictionary.swift

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -792,31 +792,36 @@ extension Dictionary {
792792
// FIXME: This code should be moved to _variant, with Dictionary.subscript
793793
// yielding `&_variant[key]`.
794794

795-
let (index, found) = _variant.mutatingFind(key)
795+
let (bucket, found) = _variant.mutatingFind(key)
796796

797797
// FIXME: Mark this entry as being modified in hash table metadata
798798
// so that lldb can recognize it's not valid.
799799

800800
// Move the old value (if any) out of storage, wrapping it into an
801801
// optional before yielding it.
802802
let native = _variant.asNative
803-
var value: Value? = found ? (native._values + index.bucket).move() : nil
803+
var value: Value?
804+
if found {
805+
value = (native._values + bucket.offset).move()
806+
} else {
807+
value = nil
808+
}
804809
yield &value
805810

806811
// Value is now potentially different. Check which one of the four
807812
// possible cases apply.
808813
switch (value, found) {
809814
case (let value?, true): // Mutation
810815
// Initialize storage to new value.
811-
(native._values + index.bucket).initialize(to: value)
816+
(native._values + bucket.offset).initialize(to: value)
812817
case (let value?, false): // Insertion
813818
// Insert the new entry at the correct place.
814819
// We've already ensured we have enough capacity.
815-
native._insert(at: index, key: key, value: value)
820+
native._insert(at: bucket, key: key, value: value)
816821
case (nil, true): // Removal
817822
// We've already removed the value; deinitialize and remove the key too.
818-
(native._values + index.bucket).deinitialize(count: 1)
819-
native._delete(at: index)
823+
(native._values + bucket.offset).deinitialize(count: 1)
824+
native._delete(at: bucket)
820825
case (nil, false): // Noop
821826
// Easy!
822827
break
@@ -848,9 +853,9 @@ extension Dictionary: ExpressibleByDictionaryLiteral {
848853
public init(dictionaryLiteral elements: (Key, Value)...) {
849854
let native = _NativeDictionary<Key, Value>(capacity: elements.count)
850855
for (key, value) in elements {
851-
let (index, found) = native.find(key)
856+
let (bucket, found) = native.find(key)
852857
_precondition(!found, "Dictionary literal contains duplicate keys")
853-
native._insert(at: index, key: key, value: value)
858+
native._insert(at: bucket, key: key, value: value)
854859
}
855860
self.init(_native: native)
856861
}
@@ -916,13 +921,13 @@ extension Dictionary {
916921
return _variant.lookup(key) ?? defaultValue()
917922
}
918923
_modify {
919-
let (index, found) = _variant.mutatingFind(key)
924+
let (bucket, found) = _variant.mutatingFind(key)
920925
let native = _variant.asNative
921926
if !found {
922927
let value = defaultValue()
923-
native._insert(at: index, key: key, value: value)
928+
native._insert(at: bucket, key: key, value: value)
924929
}
925-
let address = native._values + index.bucket
930+
let address = native._values + bucket.offset
926931
yield &address.pointee
927932
_fixLifetime(self)
928933
}
@@ -1451,7 +1456,7 @@ extension Dictionary {
14511456
}
14521457
_modify {
14531458
let index = _variant.ensureUniqueNative(preserving: position)
1454-
let address = _variant.asNative._values + index.bucket
1459+
let address = _variant.asNative._values + index.offset
14551460
yield &address.pointee
14561461
_fixLifetime(self)
14571462
}
@@ -1498,8 +1503,8 @@ extension Dictionary: Equatable where Value: Equatable {
14981503
}
14991504

15001505
for (k, v) in lhs {
1501-
let (index, found) = rhsNative.find(k)
1502-
guard found, rhsNative.uncheckedValue(at: index) == v else {
1506+
let (bucket, found) = rhsNative.find(k)
1507+
guard found, rhsNative.uncheckedValue(at: bucket) == v else {
15031508
return false
15041509
}
15051510
}
@@ -1515,8 +1520,9 @@ extension Dictionary: Equatable where Value: Equatable {
15151520
}
15161521

15171522
defer { _fixLifetime(lhsNative) }
1518-
for index in lhsNative.hashTable {
1519-
let (key, value) = lhsNative.lookup(index)
1523+
for bucket in lhsNative.hashTable {
1524+
let key = lhsNative.uncheckedKey(at: bucket)
1525+
let value = lhsNative.uncheckedValue(at: bucket)
15201526
guard
15211527
let rhsValue = rhsCocoa.lookup(_bridgeAnythingToObjectiveC(key)),
15221528
value == _forceBridgeFromObjectiveC(rhsValue, Value.self)
@@ -1805,14 +1811,14 @@ extension Dictionary.Index: Hashable {
18051811
switch _variant {
18061812
case .native(let nativeIndex):
18071813
hasher.combine(0 as UInt8)
1808-
hasher.combine(nativeIndex.bucket)
1814+
hasher.combine(nativeIndex.offset)
18091815
case .cocoa(let cocoaIndex):
18101816
_cocoaPath()
18111817
hasher.combine(1 as UInt8)
18121818
hasher.combine(cocoaIndex.currentKeyIndex)
18131819
}
18141820
#else
1815-
hasher.combine(_asNative.bucket)
1821+
hasher.combine(_asNative.offset)
18161822
#endif
18171823
}
18181824
}

stdlib/public/core/DictionaryBridging.swift

Lines changed: 64 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ final internal class _SwiftDictionaryNSEnumerator<Key: Hashable, Value>
6262

6363
@nonobjc internal var base: _NativeDictionary<Key, Value>
6464
@nonobjc internal var bridgedKeys: _BridgingHashBuffer?
65-
@nonobjc internal var nextIndex: _NativeDictionary<Key, Value>.Index
66-
@nonobjc internal var endIndex: _NativeDictionary<Key, Value>.Index
65+
@nonobjc internal var nextBucket: _NativeDictionary<Key, Value>.Bucket
66+
@nonobjc internal var endBucket: _NativeDictionary<Key, Value>.Bucket
6767

6868
@objc
6969
internal override required init() {
@@ -74,35 +74,35 @@ final internal class _SwiftDictionaryNSEnumerator<Key: Hashable, Value>
7474
_sanityCheck(_isBridgedVerbatimToObjectiveC(Key.self))
7575
self.base = base
7676
self.bridgedKeys = nil
77-
self.nextIndex = base.startIndex
78-
self.endIndex = base.endIndex
77+
self.nextBucket = base.hashTable.startBucket
78+
self.endBucket = base.hashTable.endBucket
7979
}
8080

8181
@nonobjc
8282
internal init(_ deferred: __owned _SwiftDeferredNSDictionary<Key, Value>) {
8383
_sanityCheck(!_isBridgedVerbatimToObjectiveC(Key.self))
8484
self.base = deferred.native
8585
self.bridgedKeys = deferred.bridgeKeys()
86-
self.nextIndex = base.startIndex
87-
self.endIndex = base.endIndex
86+
self.nextBucket = base.hashTable.startBucket
87+
self.endBucket = base.hashTable.endBucket
8888
}
8989

90-
private func bridgedKey(at index: _HashTable.Index) -> AnyObject {
91-
_sanityCheck(base.hashTable.isOccupied(index))
90+
private func bridgedKey(at bucket: _HashTable.Bucket) -> AnyObject {
91+
_sanityCheck(base.hashTable.isOccupied(bucket))
9292
if let bridgedKeys = self.bridgedKeys {
93-
return bridgedKeys[index]
93+
return bridgedKeys[bucket]
9494
}
95-
return _bridgeAnythingToObjectiveC(base.uncheckedKey(at: index))
95+
return _bridgeAnythingToObjectiveC(base.uncheckedKey(at: bucket))
9696
}
9797

9898
@objc
9999
internal func nextObject() -> AnyObject? {
100-
if nextIndex == endIndex {
100+
if nextBucket == endBucket {
101101
return nil
102102
}
103-
let index = nextIndex
104-
nextIndex = base.index(after: nextIndex)
105-
return self.bridgedKey(at: index)
103+
let bucket = nextBucket
104+
nextBucket = base.hashTable.occupiedBucket(after: nextBucket)
105+
return self.bridgedKey(at: bucket)
106106
}
107107

108108
@objc(countByEnumeratingWithState:objects:count:)
@@ -118,16 +118,16 @@ final internal class _SwiftDictionaryNSEnumerator<Key: Hashable, Value>
118118
theState.mutationsPtr = _fastEnumerationStorageMutationsPtr
119119
}
120120

121-
if nextIndex == endIndex {
121+
if nextBucket == endBucket {
122122
state.pointee = theState
123123
return 0
124124
}
125125

126126
// Return only a single element so that code can start iterating via fast
127127
// enumeration, terminate it, and continue via NSEnumerator.
128128
let unmanagedObjects = _UnmanagedAnyObjectArray(objects)
129-
unmanagedObjects[0] = self.bridgedKey(at: nextIndex)
130-
nextIndex = base.index(after: nextIndex)
129+
unmanagedObjects[0] = self.bridgedKey(at: nextBucket)
130+
nextBucket = base.hashTable.occupiedBucket(after: nextBucket)
131131
state.pointee = theState
132132
return 1
133133
}
@@ -141,6 +141,9 @@ final internal class _SwiftDictionaryNSEnumerator<Key: Hashable, Value>
141141
final internal class _SwiftDeferredNSDictionary<Key: Hashable, Value>
142142
: __SwiftNativeNSDictionary, _NSDictionaryCore {
143143

144+
@usableFromInline
145+
internal typealias Bucket = _HashTable.Bucket
146+
144147
// This stored property must be stored at offset zero. We perform atomic
145148
// operations on it.
146149
//
@@ -225,9 +228,9 @@ final internal class _SwiftDeferredNSDictionary<Key: Hashable, Value>
225228
let bridged = _BridgingHashBuffer.allocate(
226229
owner: native._storage,
227230
hashTable: native.hashTable)
228-
for index in native.hashTable {
229-
let object = _bridgeAnythingToObjectiveC(native.uncheckedKey(at: index))
230-
bridged.initialize(at: index, to: object)
231+
for bucket in native.hashTable {
232+
let object = _bridgeAnythingToObjectiveC(native.uncheckedKey(at: bucket))
233+
bridged.initialize(at: bucket, to: object)
231234
}
232235

233236
// Atomically put the bridged keys in place.
@@ -244,59 +247,54 @@ final internal class _SwiftDeferredNSDictionary<Key: Hashable, Value>
244247
let bridged = _BridgingHashBuffer.allocate(
245248
owner: native._storage,
246249
hashTable: native.hashTable)
247-
for index in native.hashTable {
248-
let object = _bridgeAnythingToObjectiveC(native.uncheckedValue(at: index))
249-
bridged.initialize(at: index, to: object)
250+
for bucket in native.hashTable {
251+
let value = native.uncheckedValue(at: bucket)
252+
let cocoaValue = _bridgeAnythingToObjectiveC(value)
253+
bridged.initialize(at: bucket, to: cocoaValue)
250254
}
251255

252256
// Atomically put the bridged values in place.
253257
_initializeBridgedValues(bridged)
254258
return _bridgedValues!
255259
}
256260

257-
@usableFromInline
258-
internal typealias Index = _HashTable.Index
259-
260261
@objc(copyWithZone:)
261262
internal func copy(with zone: _SwiftNSZone?) -> AnyObject {
262263
// Instances of this class should be visible outside of standard library as
263264
// having `NSDictionary` type, which is immutable.
264265
return self
265266
}
266267

267-
@objc(objectForKey:)
268-
internal func object(forKey aKey: AnyObject) -> AnyObject? {
269-
guard let nativeKey = _conditionallyBridgeFromObjectiveC(aKey, Key.self)
270-
else { return nil }
271-
272-
let (index, found) = native.find(nativeKey)
273-
guard found else { return nil }
274-
if let bridgedValues = bridgeValues() {
275-
return bridgedValues[index]
276-
}
277-
return _bridgeAnythingToObjectiveC(native.uncheckedValue(at: index))
278-
}
279-
280268
@inline(__always)
281269
private func _key(
282-
at index: Index,
270+
at bucket: Bucket,
283271
bridgedKeys: _BridgingHashBuffer?
284272
) -> AnyObject {
285273
if let bridgedKeys = bridgedKeys {
286-
return bridgedKeys[index]
274+
return bridgedKeys[bucket]
287275
}
288-
return _bridgeAnythingToObjectiveC(native.uncheckedKey(at: index))
276+
return _bridgeAnythingToObjectiveC(native.uncheckedKey(at: bucket))
289277
}
290278

291279
@inline(__always)
292280
private func _value(
293-
at index: Index,
281+
at bucket: Bucket,
294282
bridgedValues: _BridgingHashBuffer?
295283
) -> AnyObject {
296284
if let bridgedValues = bridgedValues {
297-
return bridgedValues[index]
285+
return bridgedValues[bucket]
298286
}
299-
return _bridgeAnythingToObjectiveC(native.uncheckedValue(at: index))
287+
return _bridgeAnythingToObjectiveC(native.uncheckedValue(at: bucket))
288+
}
289+
290+
@objc(objectForKey:)
291+
internal func object(forKey aKey: AnyObject) -> AnyObject? {
292+
guard let nativeKey = _conditionallyBridgeFromObjectiveC(aKey, Key.self)
293+
else { return nil }
294+
295+
let (bucket, found) = native.find(nativeKey)
296+
guard found else { return nil }
297+
return _value(at: bucket, bridgedValues: bridgeValues())
300298
}
301299

302300
@objc
@@ -324,21 +322,21 @@ final internal class _SwiftDeferredNSDictionary<Key: Hashable, Value>
324322

325323
switch (_UnmanagedAnyObjectArray(keys), _UnmanagedAnyObjectArray(objects)) {
326324
case (let unmanagedKeys?, let unmanagedObjects?):
327-
for index in native.hashTable {
328-
unmanagedKeys[i] = _key(at: index, bridgedKeys: bridgedKeys)
329-
unmanagedObjects[i] = _value(at: index, bridgedValues: bridgedValues)
325+
for bucket in native.hashTable {
326+
unmanagedKeys[i] = _key(at: bucket, bridgedKeys: bridgedKeys)
327+
unmanagedObjects[i] = _value(at: bucket, bridgedValues: bridgedValues)
330328
i += 1
331329
guard i < count else { break }
332330
}
333331
case (let unmanagedKeys?, nil):
334-
for index in native.hashTable {
335-
unmanagedKeys[i] = _key(at: index, bridgedKeys: bridgedKeys)
332+
for bucket in native.hashTable {
333+
unmanagedKeys[i] = _key(at: bucket, bridgedKeys: bridgedKeys)
336334
i += 1
337335
guard i < count else { break }
338336
}
339337
case (nil, let unmanagedObjects?):
340-
for index in native.hashTable {
341-
unmanagedObjects[i] = _value(at: index, bridgedValues: bridgedValues)
338+
for bucket in native.hashTable {
339+
unmanagedObjects[i] = _value(at: bucket, bridgedValues: bridgedValues)
342340
i += 1
343341
guard i < count else { break }
344342
}
@@ -362,9 +360,9 @@ final internal class _SwiftDeferredNSDictionary<Key: Hashable, Value>
362360
defer { _fixLifetime(self) }
363361

364362
var stop: UInt8 = 0
365-
for index in native.hashTable {
366-
let key = _key(at: index, bridgedKeys: bridgedKeys)
367-
let value = _value(at: index, bridgedValues: bridgedValues)
363+
for bucket in native.hashTable {
364+
let key = _key(at: bucket, bridgedKeys: bridgedKeys)
365+
let value = _value(at: bucket, bridgedValues: bridgedValues)
368366
block(
369367
Unmanaged.passUnretained(key),
370368
Unmanaged.passUnretained(value),
@@ -384,12 +382,15 @@ final internal class _SwiftDeferredNSDictionary<Key: Hashable, Value>
384382
objects: UnsafeMutablePointer<AnyObject>?,
385383
count: Int
386384
) -> Int {
385+
defer { _fixLifetime(self) }
386+
let hashTable = native.hashTable
387+
387388
var theState = state.pointee
388389
if theState.state == 0 {
389390
theState.state = 1 // Arbitrary non-zero value.
390391
theState.itemsPtr = AutoreleasingUnsafeMutablePointer(objects)
391392
theState.mutationsPtr = _fastEnumerationStorageMutationsPtr
392-
theState.extra.0 = CUnsignedLong(native.startIndex.bucket)
393+
theState.extra.0 = CUnsignedLong(hashTable.startBucket.offset)
393394
}
394395

395396
// Test 'objects' rather than 'count' because (a) this is very rare anyway,
@@ -400,21 +401,21 @@ final internal class _SwiftDeferredNSDictionary<Key: Hashable, Value>
400401
}
401402

402403
let unmanagedObjects = _UnmanagedAnyObjectArray(objects!)
403-
var index = _HashTable.Index(bucket: Int(theState.extra.0))
404-
let endIndex = native.endIndex
405-
_precondition(index == endIndex || native.hashTable.isOccupied(index))
404+
var bucket = _HashTable.Bucket(offset: Int(theState.extra.0))
405+
let endBucket = hashTable.endBucket
406+
_precondition(bucket == endBucket || hashTable.isOccupied(bucket))
406407
var stored = 0
407408

408409
// Only need to bridge once, so we can hoist it out of the loop.
409410
let bridgedKeys = bridgeKeys()
410411
for i in 0..<count {
411-
if index == endIndex { break }
412+
if bucket == endBucket { break }
412413

413-
unmanagedObjects[i] = _key(at: index, bridgedKeys: bridgedKeys)
414+
unmanagedObjects[i] = _key(at: bucket, bridgedKeys: bridgedKeys)
414415
stored += 1
415-
index = native.index(after: index)
416+
bucket = hashTable.occupiedBucket(after: bucket)
416417
}
417-
theState.extra.0 = CUnsignedLong(index.bucket)
418+
theState.extra.0 = CUnsignedLong(bucket.offset)
418419
state.pointee = theState
419420
return stored
420421
}

0 commit comments

Comments
 (0)