///|
/// Per-window address state defined by RFC 3284 section 5.
priv struct AddressCache {
near : Array[Int]
same : Array[Int]
mut next_near_slot : Int
}
///|
priv struct EncodedAddress {
mode : Int
value : Int
single_byte : Bool
}
///|
fn AddressCache::new() -> AddressCache {
{
near: Array::make(DEFAULT_NEAR_CACHE_SIZE, 0),
same: Array::make(DEFAULT_SAME_CACHE_SIZE * 256, 0),
next_near_slot: 0,
}
}
///|
fn AddressCache::update(self : AddressCache, address : Int) -> Unit {
self.near[self.next_near_slot] = address
self.next_near_slot = (self.next_near_slot + 1) % self.near.length()
self.same[address % self.same.length()] = address
}
///|
fn AddressCache::decode(
self : AddressCache,
cursor : ByteCursor,
here : Int,
mode : Int,
) -> Int raise VcdiffError {
let offset = cursor.offset()
let address = if mode == 0 {
read_varint(cursor)
} else if mode == 1 {
here - read_varint(cursor)
} else if mode >= 2 && mode < 2 + self.near.length() {
self.near[mode - 2] + read_varint(cursor)
} else if mode >= 2 + self.near.length() &&
mode < 2 + self.near.length() + DEFAULT_SAME_CACHE_SIZE {
let bank = mode - (2 + self.near.length())
let low = cursor.read_byte().to_int()
self.same[bank * 256 + low]
} else {
raise InvalidAddress(offset~, address=-1, limit=here)
}
if address < 0 || address >= here {
raise InvalidAddress(offset~, address~, limit=here - 1)
}
self.update(address)
address
}
///|
fn AddressCache::encode(
self : AddressCache,
address : Int,
here : Int,
) -> EncodedAddress raise VcdiffError {
if address < 0 || address >= here {
raise InvalidAddress(offset=-1, address~, limit=here - 1)
}
let mut best_mode = 0
let mut best_value = address
let here_value = here - address
if here_value < best_value {
best_mode = 1
best_value = here_value
}
for index, near_address in self.near {
if address >= near_address {
let near_value = address - near_address
if near_value < best_value {
best_mode = index + 2
best_value = near_value
}
}
}
let same_slot = address % self.same.length()
let use_same = self.same[same_slot] == address
let encoded = if use_same {
{
mode: 2 + self.near.length() + same_slot / 256,
value: same_slot % 256,
single_byte: true,
}
} else {
{ mode: best_mode, value: best_value, single_byte: false }
}
self.update(address)
encoded
}