Skip to content

Commit 1b91087

Browse files
authored
Merge pull request #1353 from ikesyo/measurement-sync-with-overlay
2 parents 6dea2bc + 38587cb commit 1b91087

File tree

2 files changed

+117
-118
lines changed

2 files changed

+117
-118
lines changed

Foundation/Measurement.swift

Lines changed: 117 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,66 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
8-
// See http://swift.org/LICENSE.txt for license information
9-
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#if DEPLOYMENT_RUNTIME_SWIFT
1314
import CoreFoundation
15+
#else
16+
@_exported import Foundation // Clang module
17+
import _SwiftCoreFoundationOverlayShims
18+
#endif
1419

1520
/// A `Measurement` is a model type that holds a `Double` value associated with a `Unit`.
1621
///
1722
/// Measurements support a large set of operators, including `+`, `-`, `*`, `/`, and a full set of comparison operators.
18-
public struct Measurement<UnitType : Unit> : ReferenceConvertible, Comparable, Equatable, CustomStringConvertible {
23+
@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
24+
public struct Measurement<UnitType : Unit> : ReferenceConvertible, Comparable, Equatable {
1925
public typealias ReferenceType = NSMeasurement
20-
26+
2127
/// The unit component of the `Measurement`.
2228
public let unit: UnitType
23-
29+
2430
/// The value component of the `Measurement`.
2531
public var value: Double
26-
32+
2733
/// Create a `Measurement` given a specified value and unit.
2834
public init(value: Double, unit: UnitType) {
2935
self.value = value
3036
self.unit = unit
3137
}
32-
38+
3339
public var hashValue: Int {
34-
return Int(bitPattern: _CFHashDouble(value))
40+
return Int(bitPattern: __CFHashDouble(value))
3541
}
36-
42+
}
43+
44+
@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
45+
extension Measurement : CustomStringConvertible, CustomDebugStringConvertible, CustomReflectable {
3746
public var description: String {
3847
return "\(value) \(unit.symbol)"
3948
}
40-
49+
4150
public var debugDescription: String {
4251
return "\(value) \(unit.symbol)"
4352
}
53+
54+
public var customMirror: Mirror {
55+
var c: [(label: String?, value: Any)] = []
56+
c.append((label: "value", value: value))
57+
c.append((label: "unit", value: unit.symbol))
58+
return Mirror(self, children: c, displayStyle: Mirror.DisplayStyle.struct)
59+
}
4460
}
4561

62+
4663
/// When a `Measurement` contains a `Dimension` unit, it gains the ability to convert between the kinds of units in that dimension.
64+
@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
4765
extension Measurement where UnitType : Dimension {
4866
/// Returns a new measurement created by converting to the specified unit.
4967
///
@@ -62,7 +80,7 @@ extension Measurement where UnitType : Dimension {
6280
}
6381
}
6482
}
65-
83+
6684
/// Converts the measurement to the specified unit.
6785
///
6886
/// - parameter otherUnit: A unit of the same `Dimension`.
@@ -97,73 +115,9 @@ extension Measurement where UnitType : Dimension {
97115
return Measurement(value: lhsValueInTermsOfBase - rhsValueInTermsOfBase, unit: type(of: lhs.unit).baseUnit())
98116
}
99117
}
100-
101-
/// Compare two measurements of the same `Dimension`.
102-
///
103-
/// If `lhs.unit == rhs.unit`, returns `lhs.value == rhs.value`. Otherwise, converts `rhs` to the same unit as `lhs` and then compares the resulting values.
104-
/// - returns: `true` if the measurements are equal.
105-
public static func ==(lhs: Measurement<UnitType>, rhs: Measurement<UnitType>) -> Bool {
106-
if lhs.unit == rhs.unit {
107-
return lhs.value == rhs.value
108-
} else {
109-
let rhsInLhs = rhs.converted(to: lhs.unit)
110-
return lhs.value == rhsInLhs.value
111-
}
112-
}
113-
114-
/// Compare two measurements of the same `Dimension`.
115-
///
116-
/// If `lhs.unit == rhs.unit`, returns `lhs.value < rhs.value`. Otherwise, converts `rhs` to the same unit as `lhs` and then compares the resulting values.
117-
/// - returns: `true` if `lhs` is less than `rhs`.
118-
public static func <(lhs: Measurement<UnitType>, rhs: Measurement<UnitType>) -> Bool {
119-
if lhs.unit == rhs.unit {
120-
return lhs.value < rhs.value
121-
} else {
122-
let rhsInLhs = rhs.converted(to: lhs.unit)
123-
return lhs.value < rhsInLhs.value
124-
}
125-
}
126-
127-
/// Compare two measurements of the same `Dimension`.
128-
///
129-
/// If `lhs.unit == rhs.unit`, returns `lhs.value > rhs.value`. Otherwise, converts `rhs` to the same unit as `lhs` and then compares the resulting values.
130-
/// - returns: `true` if `lhs` is greater than `rhs`.
131-
public static func >(lhs: Measurement<UnitType>, rhs: Measurement<UnitType>) -> Bool {
132-
if lhs.unit == rhs.unit {
133-
return lhs.value > rhs.value
134-
} else {
135-
let rhsInLhs = rhs.converted(to: lhs.unit)
136-
return lhs.value > rhsInLhs.value
137-
}
138-
}
139-
140-
/// Compare two measurements of the same `Dimension`.
141-
///
142-
/// If `lhs.unit == rhs.unit`, returns `lhs.value < rhs.value`. Otherwise, converts `rhs` to the same unit as `lhs` and then compares the resulting values.
143-
/// - returns: `true` if `lhs` is less than or equal to `rhs`.
144-
public static func <=(lhs: Measurement<UnitType>, rhs: Measurement<UnitType>) -> Bool {
145-
if lhs.unit == rhs.unit {
146-
return lhs.value <= rhs.value
147-
} else {
148-
let rhsInLhs = rhs.converted(to: lhs.unit)
149-
return lhs.value <= rhsInLhs.value
150-
}
151-
}
152-
153-
/// Compare two measurements of the same `Dimension`.
154-
///
155-
/// If `lhs.unit == rhs.unit`, returns `lhs.value >= rhs.value`. Otherwise, converts `rhs` to the same unit as `lhs` and then compares the resulting values.
156-
/// - returns: `true` if `lhs` is greater or equal to `rhs`.
157-
public static func >=(lhs: Measurement<UnitType>, rhs: Measurement<UnitType>) -> Bool {
158-
if lhs.unit == rhs.unit {
159-
return lhs.value >= rhs.value
160-
} else {
161-
let rhsInLhs = rhs.converted(to: lhs.unit)
162-
return lhs.value >= rhsInLhs.value
163-
}
164-
}
165118
}
166119

120+
@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
167121
extension Measurement {
168122
/// Add two measurements of the same Unit.
169123
/// - precondition: The `unit` of `lhs` and `rhs` must be `isEqual`.
@@ -187,6 +141,8 @@ extension Measurement {
187141
}
188142
}
189143

144+
/// Multiply a measurement by a scalar value.
145+
/// - returns: A measurement of value `lhs.value * rhs` with the same unit as `lhs`.
190146
public static func *(lhs: Measurement<UnitType>, rhs: Double) -> Measurement<UnitType> {
191147
return Measurement(value: lhs.value * rhs, unit: lhs.unit)
192148
}
@@ -209,57 +165,64 @@ extension Measurement {
209165
return Measurement(value: lhs / rhs.value, unit: rhs.unit)
210166
}
211167

212-
/// Compare two measurements of the same `Unit`.
213-
/// - returns: `true` if `lhs.value == rhs.value && lhs.unit == rhs.unit`.
214-
public static func ==(lhs: Measurement<UnitType>, rhs: Measurement<UnitType>) -> Bool {
215-
return lhs.value == rhs.value && lhs.unit == rhs.unit
216-
}
217-
218-
/// Compare two measurements of the same `Unit`.
219-
/// - note: This function does not check `==` for the `unit` property of `lhs` and `rhs`.
220-
/// - returns: `lhs.value < rhs.value`
221-
public static func <(lhs: Measurement<UnitType>, rhs: Measurement<UnitType>) -> Bool {
222-
return lhs.value < rhs.value
223-
}
224-
225-
/// Compare two measurements of the same `Unit`.
226-
/// - note: This function does not check `==` for the `unit` property of `lhs` and `rhs`.
227-
/// - returns: `lhs.value > rhs.value`
228-
public static func >(lhs: Measurement<UnitType>, rhs: Measurement<UnitType>) -> Bool {
229-
return lhs.value > rhs.value
230-
}
231-
232-
/// Compare two measurements of the same `Unit`.
233-
/// - note: This function does not check `==` for the `unit` property of `lhs` and `rhs`.
234-
/// - returns: `lhs.value <= rhs.value`
235-
public static func <=(lhs: Measurement<UnitType>, rhs: Measurement<UnitType>) -> Bool {
236-
return lhs.value <= rhs.value
168+
/// Compare two measurements of the same `Dimension`.
169+
///
170+
/// If `lhs.unit == rhs.unit`, returns `lhs.value == rhs.value`. Otherwise, converts `rhs` to the same unit as `lhs` and then compares the resulting values.
171+
/// - returns: `true` if the measurements are equal.
172+
public static func ==<LeftHandSideType, RightHandSideType>(_ lhs: Measurement<LeftHandSideType>, _ rhs: Measurement<RightHandSideType>) -> Bool {
173+
if lhs.unit == rhs.unit {
174+
return lhs.value == rhs.value
175+
} else {
176+
if let lhsDimensionalUnit = lhs.unit as? Dimension,
177+
let rhsDimensionalUnit = rhs.unit as? Dimension {
178+
if type(of: lhsDimensionalUnit).baseUnit() == type(of: rhsDimensionalUnit).baseUnit() {
179+
let lhsValueInTermsOfBase = lhsDimensionalUnit.converter.baseUnitValue(fromValue: lhs.value)
180+
let rhsValueInTermsOfBase = rhsDimensionalUnit.converter.baseUnitValue(fromValue: rhs.value)
181+
return lhsValueInTermsOfBase == rhsValueInTermsOfBase
182+
}
183+
}
184+
return false
185+
}
237186
}
238187

239188
/// Compare two measurements of the same `Unit`.
240-
/// - note: This function does not check `==` for the `unit` property of `lhs` and `rhs`.
241-
/// - returns: `lhs.value >= rhs.value`
242-
public static func >=(lhs: Measurement<UnitType>, rhs: Measurement<UnitType>) -> Bool {
243-
return lhs.value >= rhs.value
189+
/// - returns: `true` if the measurements can be compared and the `lhs` is less than the `rhs` converted value.
190+
public static func <<LeftHandSideType, RightHandSideType>(lhs: Measurement<LeftHandSideType>, rhs: Measurement<RightHandSideType>) -> Bool {
191+
if lhs.unit == rhs.unit {
192+
return lhs.value < rhs.value
193+
} else {
194+
if let lhsDimensionalUnit = lhs.unit as? Dimension,
195+
let rhsDimensionalUnit = rhs.unit as? Dimension {
196+
if type(of: lhsDimensionalUnit).baseUnit() == type(of: rhsDimensionalUnit).baseUnit() {
197+
let lhsValueInTermsOfBase = lhsDimensionalUnit.converter.baseUnitValue(fromValue: lhs.value)
198+
let rhsValueInTermsOfBase = rhsDimensionalUnit.converter.baseUnitValue(fromValue: rhs.value)
199+
return lhsValueInTermsOfBase < rhsValueInTermsOfBase
200+
}
201+
}
202+
fatalError("Attempt to compare measurements with non-equal dimensions")
203+
}
244204
}
245205
}
246206

247207
// Implementation note: similar to NSArray, NSDictionary, etc., NSMeasurement's import as an ObjC generic type is suppressed by the importer. Eventually we will need a more general purpose mechanism to correctly import generic types.
248208

249-
extension Measurement : _ObjectTypeBridgeable {
250-
public static func _isBridgedToObjectiveC() -> Bool {
251-
return true
252-
}
253-
209+
#if DEPLOYMENT_RUNTIME_SWIFT
210+
internal typealias MeasurementBridgeType = _ObjectTypeBridgeable
211+
#else
212+
internal typealias MeasurementBridgeType = _ObjectiveCBridgeable
213+
#endif
214+
215+
@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
216+
extension Measurement : MeasurementBridgeType {
254217
@_semantics("convertToObjectiveC")
255218
public func _bridgeToObjectiveC() -> NSMeasurement {
256219
return NSMeasurement(doubleValue: value, unit: unit)
257220
}
258-
221+
259222
public static func _forceBridgeFromObjectiveC(_ source: NSMeasurement, result: inout Measurement?) {
260223
result = Measurement(value: source.doubleValue, unit: source.unit as! UnitType)
261224
}
262-
225+
263226
public static func _conditionallyBridgeFromObjectiveC(_ source: NSMeasurement, result: inout Measurement?) -> Bool {
264227
if let u = source.unit as? UnitType {
265228
result = Measurement(value: source.doubleValue, unit: u)
@@ -268,13 +231,53 @@ extension Measurement : _ObjectTypeBridgeable {
268231
return false
269232
}
270233
}
271-
234+
272235
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSMeasurement?) -> Measurement {
273236
let u = source!.unit as! UnitType
274237
return Measurement(value: source!.doubleValue, unit: u)
275238
}
276239
}
277240

241+
@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
242+
extension NSMeasurement : _HasCustomAnyHashableRepresentation {
243+
// Must be @nonobjc to avoid infinite recursion during bridging.
244+
@nonobjc
245+
public func _toCustomAnyHashable() -> AnyHashable? {
246+
#if DEPLOYMENT_RUNTIME_SWIFT
247+
return AnyHashable(Measurement._unconditionallyBridgeFromObjectiveC(self))
248+
#else
249+
return AnyHashable(self as Measurement)
250+
#endif
251+
}
252+
}
253+
254+
// This workaround is required for the time being, because Swift doesn't support covariance for Measurement (26607639)
255+
@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
256+
extension MeasurementFormatter {
257+
public func string<UnitType>(from measurement: Measurement<UnitType>) -> String {
258+
if let result = string(for: measurement) {
259+
return result
260+
} else {
261+
return ""
262+
}
263+
}
264+
}
265+
266+
// @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
267+
// extension Unit : Codable {
268+
// public convenience init(from decoder: Decoder) throws {
269+
// let container = try decoder.singleValueContainer()
270+
// let symbol = try container.decode(String.self)
271+
// self.init(symbol: symbol)
272+
// }
273+
274+
// public func encode(to encoder: Encoder) throws {
275+
// var container = encoder.singleValueContainer()
276+
// try container.encode(self.symbol)
277+
// }
278+
// }
279+
280+
@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
278281
extension Measurement : Codable {
279282
private enum CodingKeys : Int, CodingKey {
280283
case value

Foundation/MeasurementFormatter.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,3 @@ open class MeasurementFormatter : Formatter, NSSecureCoding {
7777
open override func encode(with aCoder: NSCoder) { NSUnimplemented() }
7878
public static var supportsSecureCoding: Bool { return true }
7979
}
80-
81-
extension MeasurementFormatter {
82-
public func string<UnitType>(from measurement: Measurement<UnitType>) -> String { NSUnimplemented() }
83-
}

0 commit comments

Comments
 (0)