-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathTSID.kt
41 lines (35 loc) · 1.23 KB
/
TSID.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package klite
import java.lang.System.currentTimeMillis
import java.security.SecureRandom
import java.time.Instant
import java.util.concurrent.atomic.AtomicInteger
/**
* Time-Sorted unique ID, a more compact and DB index-friendly alternative to UUID.
* Add a `typealias Id<T> = TSID<T>` or `Id = TSID<Any>` in your own project.
*/
@JvmInline value class TSID<T>(val value: Long) {
companion object {
const val RANDOM_BITS = 22
const val RANDOM_MASK = 0x003fffff
val EPOCH = Instant.parse(Config.optional("TSID_EPOCH", "2022-10-21T03:45:00.000Z")).toEpochMilli()
val random = SecureRandom()
val counter = AtomicInteger()
@Volatile var lastTime = 0L
fun generateValue(): Long {
val time = (currentTimeMillis() - EPOCH) shl RANDOM_BITS
if (time != lastTime) {
counter.set(random.nextInt())
lastTime = time
}
val tail = counter.incrementAndGet() and RANDOM_MASK
return time or tail.toLong()
}
init {
Converter.use { TSID<Any>(it) }
}
}
constructor(): this(generateValue())
constructor(tsid: String): this(tsid.toLong(36))
override fun toString() = value.toString(36)
val createdAt: Instant get() = Instant.ofEpochMilli((value shr RANDOM_BITS) + EPOCH)
}