make protocol functions data type specific

motivation: it's very beneficial for the protocols to use functions with concrete types because then there's no need for specialisation. At compile time, the compiler can often not know what concrete type will be used so it needs to create a 'generic at runtime' version of the function. If however all functions on the protocol do not use generics, there's no need for a 'generic at runtime' version of the function

changes:
* change CounterHandler::increment to take Int64 instead of <DataType: BinaryInteger>
* change RecorderHandler::record to take Int64 and Double instead of <DataType: BinaryInteger> and <DataType: BinaryFloatingPoint>
* adjust example and test implementation
* adjust docs
This commit is contained in:
tomer doron 2019-04-05 10:30:46 -07:00 committed by GitHub
parent 187653d466
commit 5c1c739969
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 63 deletions

View File

@ -104,8 +104,8 @@ public protocol TimerHandler: AnyObject {
```swift
public protocol RecorderHandler: AnyObject {
func record<DataType: BinaryInteger>(_ value: DataType)
func record<DataType: BinaryFloatingPoint>(_ value: DataType)
func record(_ value: Int64)
func record(_ value: Double)
}
```
@ -120,7 +120,7 @@ class SimpleMetricsLibrary: MetricsFactory {
}
func makeRecorder(label: String, dimensions: [(String, String)], aggregate: Bool) -> RecorderHandler {
let maker:(String, [(String, String)]) -> Recorder = aggregate ? ExampleRecorder.init : ExampleGauge.init
let maker: (String, [(String, String)]) -> RecorderHandler = aggregate ? ExampleRecorder.init : ExampleGauge.init
return maker(label, dimensions)
}
@ -133,9 +133,15 @@ class SimpleMetricsLibrary: MetricsFactory {
let lock = NSLock()
var value: Int64 = 0
func increment<DataType: BinaryInteger>(_ value: DataType) {
func increment(_ value: Int64) {
self.lock.withLock {
self.value += Int64(value)
self.value += value
}
}
func reset() {
self.lock.withLock {
self.value = 0
}
}
}
@ -145,20 +151,18 @@ class SimpleMetricsLibrary: MetricsFactory {
private let lock = NSLock()
var values = [(Int64, Double)]()
func record<DataType: BinaryInteger>(_ value: DataType) {
func record(_ value: Int64) {
self.record(Double(value))
}
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
// this may loose precision, but good enough as an example
let v = Double(value)
func record(_ value: Double) {
// TODO: sliding window
lock.withLock {
values.append((Date().nanoSince1970, v))
values.append((Date().nanoSince1970, value))
self._count += 1
self._sum += v
if 0 == self._min || v < self._min { self._min = v }
if 0 == self._max || v > self._max { self._max = v }
self._sum += value
self._min = Swift.min(self._min, value)
self._max = Swift.max(self._max, value)
}
}
@ -188,13 +192,12 @@ class SimpleMetricsLibrary: MetricsFactory {
let lock = NSLock()
var _value: Double = 0
func record<DataType: BinaryInteger>(_ value: DataType) {
func record(_ value: Int64) {
self.record(Double(value))
}
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
// this may loose precision but good enough as an example
self.lock.withLock { _value = Double(value) }
func record(_ value: Double) {
self.lock.withLock { _value = value }
}
}

View File

@ -14,7 +14,7 @@
/// This is the Counter protocol a metrics library implements. It must have reference semantics
public protocol CounterHandler: AnyObject {
func increment<DataType: BinaryInteger>(_ value: DataType)
func increment(_ value: Int64)
func reset()
}
@ -35,7 +35,7 @@ public class Counter {
@inlinable
public func increment<DataType: BinaryInteger>(_ value: DataType) {
self.handler.increment(value)
self.handler.increment(Int64(value))
}
@inlinable
@ -58,8 +58,8 @@ public extension Counter {
/// This is the Recorder protocol a metrics library implements. It must have reference semantics
public protocol RecorderHandler: AnyObject {
func record<DataType: BinaryInteger>(_ value: DataType)
func record<DataType: BinaryFloatingPoint>(_ value: DataType)
func record(_ value: Int64)
func record(_ value: Double)
}
// This is the user facing Recorder API. Its behavior depends on the `RecorderHandler` implementation
@ -81,12 +81,12 @@ public class Recorder {
@inlinable
public func record<DataType: BinaryInteger>(_ value: DataType) {
self.handler.record(value)
self.handler.record(Int64(value))
}
@inlinable
public func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
self.handler.record(value)
self.handler.record(Double(value))
}
}
@ -225,7 +225,7 @@ public final class MultiplexMetricsHandler: MetricsFactory {
self.counters = factories.map { $0.makeCounter(label: label, dimensions: dimensions) }
}
func increment<DataType: BinaryInteger>(_ value: DataType) {
func increment(_ value: Int64) {
self.counters.forEach { $0.increment(value) }
}
@ -240,11 +240,11 @@ public final class MultiplexMetricsHandler: MetricsFactory {
self.recorders = factories.map { $0.makeRecorder(label: label, dimensions: dimensions, aggregate: aggregate) }
}
func record<DataType: BinaryInteger>(_ value: DataType) {
func record(_ value: Int64) {
self.recorders.forEach { $0.record(value) }
}
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
func record(_ value: Double) {
self.recorders.forEach { $0.record(value) }
}
}
@ -278,9 +278,9 @@ public final class NOOPMetricsHandler: MetricsFactory, CounterHandler, RecorderH
return self
}
public func increment<DataType: BinaryInteger>(_: DataType) {}
public func increment(_: Int64) {}
public func reset() {}
public func record<DataType: BinaryInteger>(_: DataType) {}
public func record<DataType: BinaryFloatingPoint>(_: DataType) {}
public func record(_: Int64) {}
public func record(_: Double) {}
public func recordNanoseconds(_: Int64) {}
}

View File

@ -138,27 +138,25 @@ class ExampleRecorder: RecorderHandler, CustomStringConvertible {
private let lock = NSLock()
var values = [(Int64, Double)]()
func record<DataType: BinaryInteger>(_ value: DataType) {
func record(_ value: Int64) {
self.record(Double(value))
}
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
// this may loose precision, but good enough as an example
let v = Double(value)
func record(_ value: Double) {
// TODO: sliding window
lock.withLock {
values.append((Date().nanoSince1970, v))
self.lock.withLock {
values.append((Date().nanoSince1970, value))
}
options.forEach { option in
self.options.forEach { option in
switch option {
case .count:
self.count += 1
case .sum:
self.sum += v
self.sum += value
case .min:
if 0 == self.min || v < self.min { self.min = v }
self.min = Swift.min(self.min, value)
case .max:
if 0 == self.max || v > self.max { self.max = v }
self.max = Swift.max(self.max, value)
case .quantiles(let items):
self.computeQuantiles(items)
}
@ -224,7 +222,7 @@ class ExampleRecorder: RecorderHandler, CustomStringConvertible {
self.lock.withLock {
self._quantiels.removeAll()
items.forEach { item in
if let result = Sigma.quantiles.method1(self.values.map { Double($0.1) }, probability: Double(item)) {
if let result = Sigma.quantiles.method1(self.values.map { $0.1 }, probability: Double(item)) {
self._quantiels[item] = result
}
}
@ -242,13 +240,12 @@ class ExampleGauge: RecorderHandler, CustomStringConvertible {
let lock = NSLock()
var _value: Double = 0
func record<DataType: BinaryInteger>(_ value: DataType) {
func record(_ value: Int64) {
self.record(Double(value))
}
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
// this may loose precision but good enough as an example
self.lock.withLock { _value = Double(value) }
func record(_ value: Double) {
self.lock.withLock { _value = value }
}
var description: String {

View File

@ -38,9 +38,9 @@ class SimpleMetricsLibrary: MetricsFactory {
let lock = NSLock()
var value: Int64 = 0
func increment<DataType: BinaryInteger>(_ value: DataType) {
func increment(_ value: Int64) {
self.lock.withLock {
self.value += Int64(value)
self.value += value
}
}
@ -56,20 +56,18 @@ class SimpleMetricsLibrary: MetricsFactory {
private let lock = NSLock()
var values = [(Int64, Double)]()
func record<DataType: BinaryInteger>(_ value: DataType) {
func record(_ value: Int64) {
self.record(Double(value))
}
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
// this may loose precision, but good enough as an example
let v = Double(value)
func record(_ value: Double) {
// TODO: sliding window
lock.withLock {
values.append((Date().nanoSince1970, v))
self.lock.withLock {
values.append((Date().nanoSince1970, value))
self._count += 1
self._sum += v
self._min = Swift.min(self._min, v)
self._max = Swift.max(self._max, v)
self._sum += value
self._min = Swift.min(self._min, value)
self._max = Swift.max(self._max, value)
}
}
@ -99,13 +97,12 @@ class SimpleMetricsLibrary: MetricsFactory {
let lock = NSLock()
var _value: Double = 0
func record<DataType: BinaryInteger>(_ value: DataType) {
func record(_ value: Int64) {
self.record(Double(value))
}
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
// this may loose precision but good enough as an example
self.lock.withLock { _value = Double(value) }
func record(_ value: Double) {
self.lock.withLock { _value = value }
}
}

View File

@ -60,9 +60,9 @@ internal class TestCounter: CounterHandler, Equatable {
self.dimensions = dimensions
}
func increment<DataType: BinaryInteger>(_ value: DataType) {
func increment(_ value: Int64) {
self.lock.withLock {
self.values.append((Date(), Int64(value)))
self.values.append((Date(), value))
}
print("adding \(value) to \(self.label)")
}
@ -71,6 +71,7 @@ internal class TestCounter: CounterHandler, Equatable {
self.lock.withLock {
self.values = []
}
print("reseting \(self.label)")
}
public static func == (lhs: TestCounter, rhs: TestCounter) -> Bool {
@ -94,11 +95,11 @@ internal class TestRecorder: RecorderHandler, Equatable {
self.aggregate = aggregate
}
func record<DataType: BinaryInteger>(_ value: DataType) {
func record(_ value: Int64) {
self.record(Double(value))
}
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
func record(_ value: Double) {
self.lock.withLock {
// this may loose precision but good enough as an example
values.append((Date(), Double(value)))