Skip to content

Commit 022c47f

Browse files
committed
[WIP] Use UnsafeMutablePointer for storage of CacheLookupTable
1 parent 915582d commit 022c47f

File tree

1 file changed

+36
-23
lines changed

1 file changed

+36
-23
lines changed

Sources/SwiftSyntax/CacheLookupTable.swift

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,29 @@ private struct WeakReference<T: AnyObject>: ExpressibleByNilLiteral {
3535
/// References are stored in a hash table with simple open adressing. Because
3636
/// of weak reference, unlike normal open addressing, erased bucket are simply
3737
/// turned into 'nil'.
38-
struct CacheLookupTable<T: Identifiable & AnyObject> {
39-
40-
private typealias Buffer = Array<WeakReference<T>>
38+
class CacheLookupTable<T: Identifiable & AnyObject> {
4139

4240
/// Storage for the hash table.
43-
private var buckets: Buffer
41+
private var buckets: UnsafeMutablePointer<WeakReference<T>>
42+
private var bucketCount: Int
4443

4544
/// Estimated count of inserted values. This is greater than or equal to
4645
/// the number of actually occupied buckets.
4746
/// i.e. estimatedCount >= _countOccupiedBuckets()
4847
private var estimatedCount: Int
4948

5049
init(capacity: Int = 0) {
51-
buckets = .init(repeating: nil,
52-
count: CacheLookupTable<T>._bucketCount(for: capacity))
50+
bucketCount = CacheLookupTable<T>._bucketCount(for: capacity)
51+
buckets = .allocate(capacity: bucketCount)
52+
buckets.initialize(repeating: nil, count: bucketCount)
5353
estimatedCount = 0
5454
}
5555

56+
deinit {
57+
buckets.deinitialize(count: bucketCount)
58+
buckets.deallocate()
59+
}
60+
5661
/// Constant max load factor for hash table.
5762
private static var maxLoadFactor: Double {
5863
@inline(__always) get {
@@ -88,7 +93,7 @@ struct CacheLookupTable<T: Identifiable & AnyObject> {
8893

8994
private var _bucketMask: Int {
9095
@inline(__always) get {
91-
return buckets.count &- 1
96+
return bucketCount &- 1
9297
}
9398
}
9499

@@ -117,43 +122,51 @@ struct CacheLookupTable<T: Identifiable & AnyObject> {
117122

118123
/// Reserves enough space to store the specified number of elements. Returns
119124
/// true if resizing happened.
120-
mutating func reserveCapacity(_ requiredCapacity: Int) -> Bool {
121-
let bucketCount = CacheLookupTable<T>._bucketCount(for: requiredCapacity,
122-
from: buckets.count)
123-
if (buckets.count >= bucketCount) {
125+
func reserveCapacity(_ requiredCapacity: Int) -> Bool {
126+
let requiredBucketCount =
127+
CacheLookupTable<T>._bucketCount(for: requiredCapacity, from: bucketCount)
128+
if (bucketCount >= requiredBucketCount) {
124129
return false
125130
}
126131

127132
// Slow path. Resizing.
128-
var oldBuckets = buckets
129-
buckets = .init(repeating: nil, count: bucketCount)
133+
let oldBuckets = buckets
134+
let oldBucketRange = buckets ..< buckets.advanced(by: bucketCount)
135+
136+
bucketCount = requiredBucketCount
137+
buckets = .allocate(capacity: requiredBucketCount)
138+
buckets.initialize(repeating: nil, count: requiredBucketCount)
130139

131140
// Move all nodes from the old buffer.
132-
// TODO: move(), when available.
133-
for i in 0..<oldBuckets.count {
134-
if let oldValue = oldBuckets[i].value {
135-
let pos = _findHole(oldValue.id).pos
136-
Swift.swap(&buckets[pos], &oldBuckets[i])
141+
for oldBucket in oldBucketRange {
142+
if let id = oldBucket.pointee.value?.id {
143+
let newBucket = buckets.advanced(by: _findHole(id).pos)
144+
newBucket.moveAssign(from: oldBucket, count: 1)
145+
} else {
146+
oldBucket.deinitialize(count: 1)
137147
}
138148
}
149+
150+
oldBuckets.deallocate()
151+
139152
return true
140153
}
141154

142155
/// Count the actual number of occupied buckets.
143156
@inline(__always)
144157
private func _countOccupiedBuckets() -> Int {
145158
var count = 0
146-
for i in 0 ..< buckets.count where buckets[i].value != nil {
159+
for i in 0 ..< bucketCount where buckets[i].value != nil {
147160
count &+= 1
148161
}
149162
return count
150163
}
151164

152165
/// Reserves enough space to store a single new object. Returns true if
153166
/// resizing happened.
154-
mutating private func _ensurePlusOneCapacity() -> Bool {
155-
if buckets.count >= CacheLookupTable<T>
156-
._minimalBucketCount(for: estimatedCount &+ 1) {
167+
private func _ensurePlusOneCapacity() -> Bool {
168+
if bucketCount >= CacheLookupTable<T>
169+
._minimalBucketCount(for: estimatedCount &+ 1) {
157170
return false
158171
}
159172

@@ -164,7 +177,7 @@ struct CacheLookupTable<T: Identifiable & AnyObject> {
164177

165178
/// Inserts the given object into the table.
166179
@discardableResult
167-
mutating func insert(_ obj: T) -> Bool {
180+
func insert(_ obj: T) -> Bool {
168181
var (pos, found) = _findHole(obj.id)
169182
if found {
170183
return false

0 commit comments

Comments
 (0)