Skip to content

Commit af5284c

Browse files
authored
Merge pull request #722 from CodaFi/bipass
2 parents 6ecb4e1 + 87631ee commit af5284c

File tree

4 files changed

+56
-49
lines changed

4 files changed

+56
-49
lines changed

Sources/SwiftDriver/IncrementalCompilation/BidirectionalMap.swift

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
/// Like a two-way dictionary
13+
/// Provides a bidirectional mapping between two keys.
1414
///
15-
public struct BidirectionalMap<T1: Hashable, T2: Hashable>: Equatable, Sequence {
15+
/// `BidirectionalMap` provides efficient O(1) lookups in both directions.
16+
public struct BidirectionalMap<T1: Hashable, T2: Hashable>: Equatable {
1617
private var map1: [T1: T2] = [:]
1718
private var map2: [T2: T1] = [:]
1819

@@ -63,40 +64,53 @@ public struct BidirectionalMap<T1: Hashable, T2: Hashable>: Equatable, Sequence
6364
}
6465
}
6566
}
67+
}
6668

67-
public func contains(key: T1) -> Bool {
68-
map1.keys.contains(key)
69-
}
70-
public func contains(key: T2) -> Bool {
71-
map2.keys.contains(key)
72-
}
73-
69+
extension BidirectionalMap {
70+
/// Updates the value stored in the bidirectional map for the given key,
71+
/// or adds a new set of key-value pairs if the key have an entry in the map.
72+
///
73+
/// If access to the old value is not necessary, it is more efficient to use
74+
/// the subscript operator to perform an in-place update.
75+
///
76+
/// - Parameters:
77+
/// - v: The new value to add to the two-level map.
78+
/// - key: The two-level key to associate with value.
79+
/// - Returns: The value that was replaced, or `nil` if a new key-value pair was added.
80+
@discardableResult
7481
public mutating func updateValue(_ newValue: T2, forKey key: T1) -> T2? {
75-
let oldValue = map1.updateValue(newValue, forKey: key)
76-
_ = oldValue.map {map2.removeValue(forKey: $0)}
77-
map2[newValue] = key
78-
return oldValue
82+
let old = self[key]
83+
self[key] = newValue
84+
return old
7985
}
86+
87+
/// Updates the value stored in the bidirectional map for the given key,
88+
/// or adds a new set of key-value pairs if the key have an entry in the map.
89+
///
90+
/// If access to the old value is not necessary, it is more efficient to use
91+
/// the subscript operator to perform an in-place update.
92+
///
93+
/// - Parameters:
94+
/// - v: The new value to add to the two-level map.
95+
/// - key: The two-level key to associate with value.
96+
/// - Returns: The value that was replaced, or `nil` if a new key-value pair was added.
97+
@discardableResult
8098
public mutating func updateValue(_ newValue: T1, forKey key: T2) -> T1? {
81-
let oldValue = map2.updateValue(newValue, forKey: key)
82-
_ = oldValue.map {map1.removeValue(forKey: $0)}
83-
map1[newValue] = key
84-
return oldValue
99+
let old = self[key]
100+
self[key] = newValue
101+
return old
85102
}
103+
}
86104

87-
public mutating func removeValue(forKey t1: T1) {
88-
if let t2 = map1[t1] {
89-
map2.removeValue(forKey: t2)
90-
}
91-
map1.removeValue(forKey: t1)
92-
}
93-
public mutating func removeValue(forKey t2: T2) {
94-
if let t1 = map2[t2] {
95-
map1.removeValue(forKey: t1)
96-
}
97-
map2.removeValue(forKey: t2)
98-
}
105+
extension BidirectionalMap: Sequence {
106+
/// Provides an iterator that yields pairs of the key-to-key mappings.
107+
///
108+
/// - Warning: The order of the returned mappings is not stable. In general,
109+
/// avoid iterating over a bidirectional map unless order does not
110+
/// matter for the algorithm in question.
111+
///
112+
/// - Returns: An iterator value for this bidirectional map.
99113
public func makeIterator() -> Dictionary<T1, T2>.Iterator {
100-
map1.makeIterator()
114+
self.map1.makeIterator()
101115
}
102116
}

Sources/SwiftDriver/IncrementalCompilation/ModuleDependencyGraphParts/InputDependencySourceMap.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@ import Foundation
1212
import TSCBasic
1313

1414
@_spi(Testing) public struct InputDependencySourceMap: Equatable {
15+
public typealias BiMap = BidirectionalMap<TypedVirtualPath, DependencySource>
1516

1617
/// Maps input files (e.g. .swift) to and from the DependencySource object.
1718
///
18-
// This map caches the same information as in the `OutputFileMap`, but it
19-
// optimizes the reverse lookup, and includes path interning via `DependencySource`.
20-
// Once created, it does not change.
21-
22-
public typealias BiMap = BidirectionalMap<TypedVirtualPath, DependencySource>
19+
/// This map caches the same information as in the `OutputFileMap`, but it
20+
/// optimizes the reverse lookup, and includes path interning via `DependencySource`.
21+
/// Once created, it does not change.
2322
@_spi(Testing) public let biMap: BiMap
2423

2524
/// Based on entries in the `OutputFileMap`, create the bidirectional map to map each source file

Sources/SwiftDriver/IncrementalCompilation/TwoDMap.swift

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,4 @@ public struct TwoDMap<Key1: Hashable, Key2: Hashable, Value: Equatable>: Mutable
8686
}
8787
return true
8888
}
89-
90-
public func compactMap<R>(_ fn: ((Key1, Key2), Value) -> R?) -> [R]
91-
{
92-
map1.compactMap(fn)
93-
}
9489
}

Tests/SwiftDriverTests/BidirectionalMapTests.swift

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import XCTest
1414
import SwiftDriver
1515

1616
class BidirectionalMapTests: XCTestCase {
17-
1817
func testBiDiMap() {
1918
func test(_ biMapToTest: BidirectionalMap<Int, String>) {
2019
zip(biMapToTest.map{$0}.sorted {$0.0 < $1.0}, testContents).forEach {
@@ -24,10 +23,10 @@ class BidirectionalMapTests: XCTestCase {
2423
for (i, s) in testContents.map({$0}) {
2524
XCTAssertEqual(biMapToTest[i], s)
2625
XCTAssertEqual(biMapToTest[s], i)
27-
XCTAssertTrue(biMapToTest.contains(key: i))
28-
XCTAssertTrue(biMapToTest.contains(key: s))
29-
XCTAssertFalse(biMapToTest.contains(key: -1))
30-
XCTAssertFalse(biMapToTest.contains(key: "gazorp"))
26+
XCTAssertNotNil(biMapToTest[i])
27+
XCTAssertNotNil(biMapToTest[s])
28+
XCTAssertNil(biMapToTest[-1])
29+
XCTAssertNil(biMapToTest["gazorp"])
3130
}
3231
}
3332

@@ -37,15 +36,15 @@ class BidirectionalMapTests: XCTestCase {
3736
biMap[i] = s
3837
}
3938
test(biMap)
40-
biMap.removeValue(forKey: testContents.count)
39+
biMap[testContents.count] = nil
4140
test(biMap)
42-
biMap.removeValue(forKey: "gazorp")
41+
biMap["gazorp"] = nil
4342
test(biMap)
4443

4544
let removed = testContents.removeFirst()
4645
var biMap2 = biMap
47-
biMap.removeValue(forKey: removed.0)
48-
biMap2.removeValue(forKey: removed.1)
46+
biMap[removed.0] = nil
47+
biMap2[removed.1] = nil
4948
test(biMap)
5049
test(biMap2)
5150
}

0 commit comments

Comments
 (0)