Skip to content

Commit aa85fc7

Browse files
feature: Registry holds unit name map
1 parent 9470e2b commit aa85fc7

3 files changed

Lines changed: 48 additions & 13 deletions

File tree

Sources/Units/Registry.swift

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,26 @@ internal class Registry {
44
// TODO: Should we eliminate this singleton and make clients keep track?
55
internal static let instance = Registry()
66

7-
// Store units as a dictionary based on symbol for fast access
8-
// TODO: Change to Unit to avoid creating multiple Units in memory
9-
private var units: [String: DefinedUnit]
7+
// Quick access based on symbol
8+
private var symbolMap: [String: DefinedUnit]
9+
// Quick access based on name
10+
private var nameMap: [String: DefinedUnit]
11+
1012
private init() {
11-
units = [:]
13+
symbolMap = [:]
14+
nameMap = [:]
1215
for defaultUnit in Registry.defaultUnits {
1316
// Protect against double-defining symbols
14-
if units[defaultUnit.symbol] != nil {
17+
if symbolMap[defaultUnit.symbol] != nil {
1518
fatalError("Duplicate symbol: \(defaultUnit.symbol)")
1619
}
17-
units[defaultUnit.symbol] = defaultUnit
20+
symbolMap[defaultUnit.symbol] = defaultUnit
21+
22+
// Protect against double-defining names
23+
if nameMap[defaultUnit.name] != nil {
24+
fatalError("Duplicate name: \(defaultUnit.name)")
25+
}
26+
nameMap[defaultUnit.name] = defaultUnit
1827
}
1928
}
2029

@@ -28,21 +37,30 @@ internal class Registry {
2837
guard exponent != 0 else {
2938
continue
3039
}
31-
let definedUnit = try definedUnitFromSymbol(symbol: definedUnitSymbol)
40+
let definedUnit = try getUnit(bySymbol: definedUnitSymbol)
3241
compositeUnits[definedUnit] = exponent
3342
}
3443
return compositeUnits
3544
}
3645

3746
/// Returns a defined unit given a defined unit symbol. It is expected that the caller has
3847
/// verified that this is not a composite unit.
39-
internal func definedUnitFromSymbol(symbol: String) throws -> DefinedUnit {
40-
guard let definedUnit = units[symbol] else {
48+
internal func getUnit(bySymbol symbol: String) throws -> DefinedUnit {
49+
guard let definedUnit = symbolMap[symbol] else {
4150
throw UnitError.unitNotFound(message: "Symbol '\(symbol)' not recognized")
4251
}
4352
return definedUnit
4453
}
4554

55+
/// Returns a defined unit given a defined unit name. It is expected that the caller has
56+
/// verified that this is not a composite unit.
57+
internal func getUnit(byName name: String) throws -> DefinedUnit {
58+
guard let definedUnit = nameMap[name] else {
59+
throw UnitError.unitNotFound(message: "Name '\(name)' not recognized")
60+
}
61+
return definedUnit
62+
}
63+
4664
/// Define a new unit to add to the registry
4765
/// - parameter name: The string name of the unit.
4866
/// - parameter symbol: The string symbol of the unit. Symbols may not contain the characters `*`, `/`, or `^`.
@@ -64,16 +82,22 @@ internal class Registry {
6482
constant: constant
6583
)
6684
// Protect against double-defining symbols
67-
if units[symbol] != nil {
85+
if symbolMap[symbol] != nil {
6886
throw UnitError.invalidSymbol(message: "Duplicate symbol: \(symbol)")
6987
}
70-
units[symbol] = newUnit
88+
symbolMap[symbol] = newUnit
89+
90+
// Protect against double-defining names
91+
if nameMap[name] != nil {
92+
fatalError("Duplicate name: \(name)")
93+
}
94+
nameMap[name] = newUnit
7195
}
7296

7397
/// Returns all units currently defined by the registry
7498
internal func allUnits() -> [Unit] {
7599
var allUnits = [Unit]()
76-
for (_, unit) in units {
100+
for (_, unit) in symbolMap {
77101
allUnits.append(Unit(definedBy: unit))
78102
}
79103
return allUnits

Sources/Units/Unit/Unit.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public struct Unit {
3232
self.init(composedOf: compositeUnits)
3333
}
3434
} else {
35-
let definedUnit = try Registry.instance.definedUnitFromSymbol(symbol: symbol)
35+
let definedUnit = try Registry.instance.getUnit(bySymbol: symbol)
3636
self.init(definedBy: definedUnit)
3737
}
3838
}

Tests/UnitsTests/UnitTests.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,17 @@ final class UnitTests: XCTestCase {
274274
)
275275
}
276276

277+
func testFromName() throws {
278+
XCTAssertEqual(
279+
try Unit(fromName: "meter"),
280+
Unit.meter
281+
)
282+
283+
XCTAssertThrowsError(
284+
try Unit(fromSymbol: "notAUnit")
285+
)
286+
}
287+
277288
func testLosslessStringConvertible() throws {
278289
XCTAssertEqual(
279290
Unit(Unit.meter.description),

0 commit comments

Comments
 (0)