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:
parent
187653d466
commit
5c1c739969
37
README.md
37
README.md
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
|
|
|
|||
Loading…
Reference in New Issue