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
|
```swift
|
||||||
public protocol RecorderHandler: AnyObject {
|
public protocol RecorderHandler: AnyObject {
|
||||||
func record<DataType: BinaryInteger>(_ value: DataType)
|
func record(_ value: Int64)
|
||||||
func record<DataType: BinaryFloatingPoint>(_ value: DataType)
|
func record(_ value: Double)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -120,7 +120,7 @@ class SimpleMetricsLibrary: MetricsFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeRecorder(label: String, dimensions: [(String, String)], aggregate: Bool) -> RecorderHandler {
|
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)
|
return maker(label, dimensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,9 +133,15 @@ class SimpleMetricsLibrary: MetricsFactory {
|
||||||
|
|
||||||
let lock = NSLock()
|
let lock = NSLock()
|
||||||
var value: Int64 = 0
|
var value: Int64 = 0
|
||||||
func increment<DataType: BinaryInteger>(_ value: DataType) {
|
func increment(_ value: Int64) {
|
||||||
self.lock.withLock {
|
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()
|
private let lock = NSLock()
|
||||||
var values = [(Int64, Double)]()
|
var values = [(Int64, Double)]()
|
||||||
func record<DataType: BinaryInteger>(_ value: DataType) {
|
func record(_ value: Int64) {
|
||||||
self.record(Double(value))
|
self.record(Double(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
|
func record(_ value: Double) {
|
||||||
// this may loose precision, but good enough as an example
|
|
||||||
let v = Double(value)
|
|
||||||
// TODO: sliding window
|
// TODO: sliding window
|
||||||
lock.withLock {
|
lock.withLock {
|
||||||
values.append((Date().nanoSince1970, v))
|
values.append((Date().nanoSince1970, value))
|
||||||
self._count += 1
|
self._count += 1
|
||||||
self._sum += v
|
self._sum += value
|
||||||
if 0 == self._min || v < self._min { self._min = v }
|
self._min = Swift.min(self._min, value)
|
||||||
if 0 == self._max || v > self._max { self._max = v }
|
self._max = Swift.max(self._max, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,13 +192,12 @@ class SimpleMetricsLibrary: MetricsFactory {
|
||||||
|
|
||||||
let lock = NSLock()
|
let lock = NSLock()
|
||||||
var _value: Double = 0
|
var _value: Double = 0
|
||||||
func record<DataType: BinaryInteger>(_ value: DataType) {
|
func record(_ value: Int64) {
|
||||||
self.record(Double(value))
|
self.record(Double(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
|
func record(_ value: Double) {
|
||||||
// this may loose precision but good enough as an example
|
self.lock.withLock { _value = value }
|
||||||
self.lock.withLock { _value = Double(value) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
/// This is the Counter protocol a metrics library implements. It must have reference semantics
|
/// This is the Counter protocol a metrics library implements. It must have reference semantics
|
||||||
public protocol CounterHandler: AnyObject {
|
public protocol CounterHandler: AnyObject {
|
||||||
func increment<DataType: BinaryInteger>(_ value: DataType)
|
func increment(_ value: Int64)
|
||||||
func reset()
|
func reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ public class Counter {
|
||||||
|
|
||||||
@inlinable
|
@inlinable
|
||||||
public func increment<DataType: BinaryInteger>(_ value: DataType) {
|
public func increment<DataType: BinaryInteger>(_ value: DataType) {
|
||||||
self.handler.increment(value)
|
self.handler.increment(Int64(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
@inlinable
|
@inlinable
|
||||||
|
|
@ -58,8 +58,8 @@ public extension Counter {
|
||||||
|
|
||||||
/// This is the Recorder protocol a metrics library implements. It must have reference semantics
|
/// This is the Recorder protocol a metrics library implements. It must have reference semantics
|
||||||
public protocol RecorderHandler: AnyObject {
|
public protocol RecorderHandler: AnyObject {
|
||||||
func record<DataType: BinaryInteger>(_ value: DataType)
|
func record(_ value: Int64)
|
||||||
func record<DataType: BinaryFloatingPoint>(_ value: DataType)
|
func record(_ value: Double)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the user facing Recorder API. Its behavior depends on the `RecorderHandler` implementation
|
// This is the user facing Recorder API. Its behavior depends on the `RecorderHandler` implementation
|
||||||
|
|
@ -81,12 +81,12 @@ public class Recorder {
|
||||||
|
|
||||||
@inlinable
|
@inlinable
|
||||||
public func record<DataType: BinaryInteger>(_ value: DataType) {
|
public func record<DataType: BinaryInteger>(_ value: DataType) {
|
||||||
self.handler.record(value)
|
self.handler.record(Int64(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
@inlinable
|
@inlinable
|
||||||
public func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
|
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) }
|
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) }
|
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) }
|
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) }
|
self.recorders.forEach { $0.record(value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
|
func record(_ value: Double) {
|
||||||
self.recorders.forEach { $0.record(value) }
|
self.recorders.forEach { $0.record(value) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -278,9 +278,9 @@ public final class NOOPMetricsHandler: MetricsFactory, CounterHandler, RecorderH
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
public func increment<DataType: BinaryInteger>(_: DataType) {}
|
public func increment(_: Int64) {}
|
||||||
public func reset() {}
|
public func reset() {}
|
||||||
public func record<DataType: BinaryInteger>(_: DataType) {}
|
public func record(_: Int64) {}
|
||||||
public func record<DataType: BinaryFloatingPoint>(_: DataType) {}
|
public func record(_: Double) {}
|
||||||
public func recordNanoseconds(_: Int64) {}
|
public func recordNanoseconds(_: Int64) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -138,27 +138,25 @@ class ExampleRecorder: RecorderHandler, CustomStringConvertible {
|
||||||
|
|
||||||
private let lock = NSLock()
|
private let lock = NSLock()
|
||||||
var values = [(Int64, Double)]()
|
var values = [(Int64, Double)]()
|
||||||
func record<DataType: BinaryInteger>(_ value: DataType) {
|
func record(_ value: Int64) {
|
||||||
self.record(Double(value))
|
self.record(Double(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
|
func record(_ value: Double) {
|
||||||
// this may loose precision, but good enough as an example
|
|
||||||
let v = Double(value)
|
|
||||||
// TODO: sliding window
|
// TODO: sliding window
|
||||||
lock.withLock {
|
self.lock.withLock {
|
||||||
values.append((Date().nanoSince1970, v))
|
values.append((Date().nanoSince1970, value))
|
||||||
}
|
}
|
||||||
options.forEach { option in
|
self.options.forEach { option in
|
||||||
switch option {
|
switch option {
|
||||||
case .count:
|
case .count:
|
||||||
self.count += 1
|
self.count += 1
|
||||||
case .sum:
|
case .sum:
|
||||||
self.sum += v
|
self.sum += value
|
||||||
case .min:
|
case .min:
|
||||||
if 0 == self.min || v < self.min { self.min = v }
|
self.min = Swift.min(self.min, value)
|
||||||
case .max:
|
case .max:
|
||||||
if 0 == self.max || v > self.max { self.max = v }
|
self.max = Swift.max(self.max, value)
|
||||||
case .quantiles(let items):
|
case .quantiles(let items):
|
||||||
self.computeQuantiles(items)
|
self.computeQuantiles(items)
|
||||||
}
|
}
|
||||||
|
|
@ -224,7 +222,7 @@ class ExampleRecorder: RecorderHandler, CustomStringConvertible {
|
||||||
self.lock.withLock {
|
self.lock.withLock {
|
||||||
self._quantiels.removeAll()
|
self._quantiels.removeAll()
|
||||||
items.forEach { item in
|
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
|
self._quantiels[item] = result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -242,13 +240,12 @@ class ExampleGauge: RecorderHandler, CustomStringConvertible {
|
||||||
|
|
||||||
let lock = NSLock()
|
let lock = NSLock()
|
||||||
var _value: Double = 0
|
var _value: Double = 0
|
||||||
func record<DataType: BinaryInteger>(_ value: DataType) {
|
func record(_ value: Int64) {
|
||||||
self.record(Double(value))
|
self.record(Double(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
|
func record(_ value: Double) {
|
||||||
// this may loose precision but good enough as an example
|
self.lock.withLock { _value = value }
|
||||||
self.lock.withLock { _value = Double(value) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var description: String {
|
var description: String {
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,9 @@ class SimpleMetricsLibrary: MetricsFactory {
|
||||||
|
|
||||||
let lock = NSLock()
|
let lock = NSLock()
|
||||||
var value: Int64 = 0
|
var value: Int64 = 0
|
||||||
func increment<DataType: BinaryInteger>(_ value: DataType) {
|
func increment(_ value: Int64) {
|
||||||
self.lock.withLock {
|
self.lock.withLock {
|
||||||
self.value += Int64(value)
|
self.value += value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,20 +56,18 @@ class SimpleMetricsLibrary: MetricsFactory {
|
||||||
|
|
||||||
private let lock = NSLock()
|
private let lock = NSLock()
|
||||||
var values = [(Int64, Double)]()
|
var values = [(Int64, Double)]()
|
||||||
func record<DataType: BinaryInteger>(_ value: DataType) {
|
func record(_ value: Int64) {
|
||||||
self.record(Double(value))
|
self.record(Double(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
|
func record(_ value: Double) {
|
||||||
// this may loose precision, but good enough as an example
|
|
||||||
let v = Double(value)
|
|
||||||
// TODO: sliding window
|
// TODO: sliding window
|
||||||
lock.withLock {
|
self.lock.withLock {
|
||||||
values.append((Date().nanoSince1970, v))
|
values.append((Date().nanoSince1970, value))
|
||||||
self._count += 1
|
self._count += 1
|
||||||
self._sum += v
|
self._sum += value
|
||||||
self._min = Swift.min(self._min, v)
|
self._min = Swift.min(self._min, value)
|
||||||
self._max = Swift.max(self._max, v)
|
self._max = Swift.max(self._max, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,13 +97,12 @@ class SimpleMetricsLibrary: MetricsFactory {
|
||||||
|
|
||||||
let lock = NSLock()
|
let lock = NSLock()
|
||||||
var _value: Double = 0
|
var _value: Double = 0
|
||||||
func record<DataType: BinaryInteger>(_ value: DataType) {
|
func record(_ value: Int64) {
|
||||||
self.record(Double(value))
|
self.record(Double(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
|
func record(_ value: Double) {
|
||||||
// this may loose precision but good enough as an example
|
self.lock.withLock { _value = value }
|
||||||
self.lock.withLock { _value = Double(value) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,9 +60,9 @@ internal class TestCounter: CounterHandler, Equatable {
|
||||||
self.dimensions = dimensions
|
self.dimensions = dimensions
|
||||||
}
|
}
|
||||||
|
|
||||||
func increment<DataType: BinaryInteger>(_ value: DataType) {
|
func increment(_ value: Int64) {
|
||||||
self.lock.withLock {
|
self.lock.withLock {
|
||||||
self.values.append((Date(), Int64(value)))
|
self.values.append((Date(), value))
|
||||||
}
|
}
|
||||||
print("adding \(value) to \(self.label)")
|
print("adding \(value) to \(self.label)")
|
||||||
}
|
}
|
||||||
|
|
@ -71,6 +71,7 @@ internal class TestCounter: CounterHandler, Equatable {
|
||||||
self.lock.withLock {
|
self.lock.withLock {
|
||||||
self.values = []
|
self.values = []
|
||||||
}
|
}
|
||||||
|
print("reseting \(self.label)")
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func == (lhs: TestCounter, rhs: TestCounter) -> Bool {
|
public static func == (lhs: TestCounter, rhs: TestCounter) -> Bool {
|
||||||
|
|
@ -94,11 +95,11 @@ internal class TestRecorder: RecorderHandler, Equatable {
|
||||||
self.aggregate = aggregate
|
self.aggregate = aggregate
|
||||||
}
|
}
|
||||||
|
|
||||||
func record<DataType: BinaryInteger>(_ value: DataType) {
|
func record(_ value: Int64) {
|
||||||
self.record(Double(value))
|
self.record(Double(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
|
func record(_ value: Double) {
|
||||||
self.lock.withLock {
|
self.lock.withLock {
|
||||||
// this may loose precision but good enough as an example
|
// this may loose precision but good enough as an example
|
||||||
values.append((Date(), Double(value)))
|
values.append((Date(), Double(value)))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue