Skip to content

Commit 1b5803c

Browse files
committed
[WIP] Use UnsafeMutablePointer for storage of CacheLookupTable
1 parent 9185049 commit 1b5803c

File tree

1 file changed

+37
-22
lines changed

1 file changed

+37
-22
lines changed

Sources/SwiftSyntax/CacheLookupTable.swift

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2018 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -35,24 +35,31 @@ 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> {
38+
class CacheLookupTable<T: Identifiable & AnyObject> {
3939

4040
private typealias Buffer = Array<WeakReference<T>>
4141

4242
/// Storage for the hash table.
43-
private var buckets: Buffer
43+
private var buckets: UnsafeMutablePointer<WeakReference<T>>
44+
private var bucketCount: Int
4445

4546
/// Estimated count of inserted values. This is greater than or equal to
4647
/// the number of the acually occupied buckets.
4748
/// i.e. estimatedCount >= _countOccupiedBuckets()
4849
private var estimatedCount: Int
4950

5051
init(capacity: Int = 0) {
51-
buckets = .init(repeating: nil,
52-
count: CacheLookupTable<T>._bucketCount(for: capacity))
52+
bucketCount = CacheLookupTable<T>._bucketCount(for: capacity)
53+
buckets = .allocate(capacity: bucketCount)
54+
buckets.initialize(repeating: nil, count: bucketCount)
5355
estimatedCount = 0
5456
}
5557

58+
deinit {
59+
buckets.deinitialize(count: bucketCount)
60+
buckets.deallocate()
61+
}
62+
5663
/// Constant max load factor for hash table.
5764
private static var maxLoadFactor: Double {
5865
@inline(__always) get {
@@ -88,7 +95,7 @@ struct CacheLookupTable<T: Identifiable & AnyObject> {
8895

8996
private var _bucketMask: Int {
9097
@inline(__always) get {
91-
return buckets.count &- 1
98+
return bucketCount &- 1
9299
}
93100
}
94101

@@ -116,43 +123,51 @@ struct CacheLookupTable<T: Identifiable & AnyObject> {
116123

117124
/// Reserves enough space to store the specified number of elements. Returns
118125
/// true if resizing happened.
119-
mutating func reserveCapacity(_ requiredCapacity: Int) -> Bool {
120-
let bucketCount = CacheLookupTable<T>._bucketCount(for: requiredCapacity,
121-
from: buckets.count)
122-
if (buckets.count >= bucketCount) {
126+
func reserveCapacity(_ requiredCapacity: Int) -> Bool {
127+
let requiredBucketCount =
128+
CacheLookupTable<T>._bucketCount(for: requiredCapacity, from: bucketCount)
129+
if (bucketCount >= requiredBucketCount) {
123130
return false
124131
}
125132

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

130141
// Move all nodes from the old buffer.
131-
// TODO: move(), when available.
132-
for i in 0..<oldBuckets.count {
133-
if let oldValue = oldBuckets[i].value {
134-
let pos = _findHole(oldValue.id).pos
135-
Swift.swap(&buckets[pos], &oldBuckets[i])
142+
for oldBucket in oldBucketRange {
143+
if let id = oldBucket.pointee.value?.id {
144+
let newBucket = buckets.advanced(by: _findHole(id).pos)
145+
newBucket.moveAssign(from: oldBucket, count: 1)
146+
} else {
147+
oldBucket.deinitialize(count: 1)
136148
}
137149
}
150+
151+
oldBuckets.deallocate()
152+
138153
return true
139154
}
140155

141156
/// Count the actual number of occupied buckets.
142157
@inline(__always)
143158
private func _countOccupiedBuckets() -> Int {
144159
var count = 0
145-
for i in 0 ..< buckets.count where buckets[i].value != nil {
160+
for i in 0 ..< bucketCount where buckets[i].value != nil {
146161
count &+= 1
147162
}
148163
return count
149164
}
150165

151166
/// Reserves enough space to store a single new value. Returns true if
152167
/// resizing happened.
153-
mutating private func _ensurePlusOneCapacity() -> Bool {
154-
if buckets.count >= CacheLookupTable<T>
155-
._minimalBucketCount(for: estimatedCount &+ 1) {
168+
private func _ensurePlusOneCapacity() -> Bool {
169+
if bucketCount >= CacheLookupTable<T>
170+
._minimalBucketCount(for: estimatedCount &+ 1) {
156171
return false
157172
}
158173

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

165180
/// Inserts the given object into the table.
166181
@discardableResult
167-
mutating func insert(_ obj: T) -> Bool {
182+
func insert(_ obj: T) -> Bool {
168183
var (pos, found) = _findHole(obj.id)
169184
if found {
170185
return false

0 commit comments

Comments
 (0)