valueAt

fun valueAt(id: RgaId): V

The element id carries — O(1), and the only way to read one element's value.

toList and entries are the whole-log readers: each builds two eager Θ(N) lists, so a caller that wants the first few elements pays for all of them. This is the piecewise form, and it exists so such a caller can walk sequence lazily — filter tombstones, take what it needs, and resolve only those.

Throws

if id is not present — it was never inserted, or it was compacted away (compactedIds) and its Insert op is gone. A tombstoned id is still present and still resolves: the value is retained until compaction, which is what lets a caller read what it is about to remove.

Samples

val a = ReplicaId("A")

var log = Rga.empty<String>()
var after = RgaId.HEAD
val ids = (1..5).map { i ->
    val (next, op) = log.insertAfter(replica = a, after = after, value = "entry-$i")
    log = next
    after = op.id
    op.id
}

// Remove the first entry. It is TOMBSTONED, not gone — still in `sequence`, and its value
// is still readable — which is exactly why the walk has to filter `tombstones` itself.
log = checkNotNull(log.removeAt(0)).first
check(ids.first() in log.tombstones)
check(log.valueAt(ids.first()) == "entry-1")

// The two oldest VISIBLE entries, resolving only those two.
val head = log.sequence.asSequence()
    .filter { id -> id !in log.tombstones }
    .take(2)
    .map { id -> log.valueAt(id) }
    .toList()
check(head == listOf("entry-2", "entry-3"))