-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Logging Metadata #52
Logging Metadata #52
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.juul.tuulbox.logging | ||
|
||
/** | ||
* Marker interface to strongly type metadata with its key. Proper usage is | ||
* to create `object`s or `enum class`es when implementing this type. | ||
*/ | ||
public interface Key<T : Any> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package com.juul.tuulbox.logging | ||
|
||
internal class Metadata : ReadMetadata, WriteMetadata { | ||
private val storedData = mutableMapOf<Key<*>, Any>() | ||
|
||
@Suppress("UNCHECKED_CAST") | ||
public override operator fun <T : Any> get(key: Key<T>): T? = | ||
storedData[key] as? T | ||
|
||
public override operator fun <T : Any> set(key: Key<T>, value: T) { | ||
storedData[key] = value | ||
} | ||
|
||
public override fun copy(): Metadata = Metadata().also { copy -> | ||
copy.storedData += this.storedData | ||
} | ||
|
||
internal fun clear() { | ||
storedData.clear() | ||
} | ||
|
||
override fun equals(other: Any?): Boolean = other is Metadata && storedData == other.storedData | ||
override fun hashCode(): Int = storedData.hashCode() | ||
} | ||
|
||
/** | ||
* Additional data associated with a log. It's important that [Logger] instances do NOT hold onto references | ||
* to [ReadMetadata] arguments after the function returns. If a [ReadMetadata] reference must be kept after | ||
* function return, create a [copy]. | ||
*/ | ||
public interface ReadMetadata { | ||
public operator fun <T : Any> get(key: Key<T>): T? | ||
public fun copy(): ReadMetadata | ||
} | ||
|
||
/** | ||
* Additional data associated with a log. It's important that [Log] calls do NOT hold onto references | ||
* to [WriteMetadata] arguments after the lambda returns. | ||
*/ | ||
public interface WriteMetadata { | ||
public operator fun <T : Any> set(key: Key<T>, value: T) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.juul.tuulbox.logging | ||
|
||
import kotlinx.atomicfu.locks.reentrantLock | ||
import kotlinx.atomicfu.locks.withLock | ||
|
||
/** While a [Pool] is logically thread safe, Kotlin/Native's memory model requires @ThreadLocal on instances of this. */ | ||
internal class Pool<T>( | ||
private val factory: () -> T, | ||
private val refurbish: (T) -> Unit, | ||
) { | ||
private val lock = reentrantLock() | ||
private val cache = ArrayDeque<T>() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does the queue (as apposed to an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Re. Re.
The solution here, albeit ugly, should be fast on every platform. Effectively...
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the incredibly thorough explanation. Super clever approach with the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And yet, somehow, despite writing a small essay, I managed to miss the original question. It should be safe to nest log calls, both inside a |
||
|
||
fun borrow(): T = lock.withLock { cache.removeLastOrNull() } ?: factory() | ||
fun recycle(value: T) { | ||
refurbish(value) | ||
lock.withLock { cache.addLast(value) } | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL of
::<class_name>
constructor syntax, so cool!