|
|
@ -24,10 +24,10 @@ def IdTableEntry = map::Entry(<Key, usz>) @private; |
|
|
|
const usz CACHE_NCYCLES = (usz)(SIZE * 2.0/3.0); |
|
|
|
const usz CACHE_NCYCLES = (usz)(SIZE * 2.0/3.0); |
|
|
|
|
|
|
|
|
|
|
|
struct Cache { |
|
|
|
struct Cache { |
|
|
|
BitArr present, used; |
|
|
|
BitArr present, used; |
|
|
|
IdTable table; |
|
|
|
IdTable table; |
|
|
|
Value[] pool; |
|
|
|
Value[] pool; |
|
|
|
usz cycle_count; |
|
|
|
usz cycle_count; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Every CACHE_CYCLES operations mark as not-present the unused elements |
|
|
|
// Every CACHE_CYCLES operations mark as not-present the unused elements |
|
|
@ -44,32 +44,32 @@ macro Cache.cycle(&cache) @private { |
|
|
|
|
|
|
|
|
|
|
|
fn void! Cache.init(&cache) |
|
|
|
fn void! Cache.init(&cache) |
|
|
|
{ |
|
|
|
{ |
|
|
|
cache.table.new_init(capacity: SIZE); |
|
|
|
cache.table.new_init(capacity: SIZE); |
|
|
|
// FIXME: this shit is SLOW |
|
|
|
// FIXME: this shit is SLOW |
|
|
|
foreach (idx, bit : cache.used) { cache.used[idx] = false; } |
|
|
|
foreach (idx, bit : cache.used) { cache.used[idx] = false; } |
|
|
|
foreach (idx, bit : cache.present) { cache.present[idx] = false; } |
|
|
|
foreach (idx, bit : cache.present) { cache.present[idx] = false; } |
|
|
|
cache.pool = mem::new_array(Value, SIZE); |
|
|
|
cache.pool = mem::new_array(Value, SIZE); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn void Cache.free(&cache) |
|
|
|
fn void Cache.free(&cache) |
|
|
|
{ |
|
|
|
{ |
|
|
|
(void)cache.table.free(); |
|
|
|
(void)cache.table.free(); |
|
|
|
(void)mem::free(cache.pool); |
|
|
|
(void)mem::free(cache.pool); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn Value*! Cache.search(&cache, Key id) |
|
|
|
fn Value*! Cache.search(&cache, Key id) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// get_entry() faults on miss |
|
|
|
// get_entry() faults on miss |
|
|
|
IdTableEntry* entry = cache.table.get_entry(id)!; |
|
|
|
IdTableEntry* entry = cache.table.get_entry(id)!; |
|
|
|
|
|
|
|
|
|
|
|
/* MISS */ |
|
|
|
/* MISS */ |
|
|
|
if (entry.key != id) { |
|
|
|
if (entry.key != id) { |
|
|
|
return SearchResult.MISSING?; |
|
|
|
return SearchResult.MISSING?; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* MISS, the data is not valid (not present) */ |
|
|
|
/* MISS, the data is not valid (not present) */ |
|
|
|
if (!cache.present[entry.value]) { |
|
|
|
if (!cache.present[entry.value]) { |
|
|
|
// if the data is not present but it is still in the table, remove it |
|
|
|
// if the data is not present but it is still in the table, remove it |
|
|
|
cache.table.remove(id)!; |
|
|
|
cache.table.remove(id)!; |
|
|
|
return SearchResult.MISSING?; |
|
|
|
return SearchResult.MISSING?; |
|
|
|
} |
|
|
|
} |
|
|
@ -83,8 +83,8 @@ fn Value*! Cache.search(&cache, Key id) |
|
|
|
/* If there is no free space left then just return the first position */ |
|
|
|
/* If there is no free space left then just return the first position */ |
|
|
|
fn usz Cache.get_free_spot(&cache) @private |
|
|
|
fn usz Cache.get_free_spot(&cache) @private |
|
|
|
{ |
|
|
|
{ |
|
|
|
const BITS = $typeof(cache.present.data[0]).sizeof*8; |
|
|
|
const BITS = $typeof(cache.present.data[0]).sizeof*8; |
|
|
|
foreach (idx, d: cache.present.data) { |
|
|
|
foreach (idx, d: cache.present.data) { |
|
|
|
if (d.clz() != BITS) { |
|
|
|
if (d.clz() != BITS) { |
|
|
|
return idx*BITS + BITS-d.clz(); |
|
|
|
return idx*BITS + BITS-d.clz(); |
|
|
|
} |
|
|
|
} |
|
|
@ -94,7 +94,7 @@ fn usz Cache.get_free_spot(&cache) @private |
|
|
|
|
|
|
|
|
|
|
|
fn Value*! Cache.insert_at(&cache, Value *g, Key id, usz index) @private |
|
|
|
fn Value*! Cache.insert_at(&cache, Value *g, Key id, usz index) @private |
|
|
|
{ |
|
|
|
{ |
|
|
|
// TODO: verify index, g and id |
|
|
|
// TODO: verify index, g and id |
|
|
|
Value* spot; |
|
|
|
Value* spot; |
|
|
|
|
|
|
|
|
|
|
|
/* Set used and present */ |
|
|
|
/* Set used and present */ |
|
|
@ -117,17 +117,17 @@ fn Value*! Cache.insert_new(&cache, Value* g, Key id) |
|
|
|
|
|
|
|
|
|
|
|
fn Value*! Cache.get_or_insert(&cache, Value* g, Key id, bool *is_new = null) |
|
|
|
fn Value*! Cache.get_or_insert(&cache, Value* g, Key id, bool *is_new = null) |
|
|
|
{ |
|
|
|
{ |
|
|
|
Value*! c = cache.search(id); |
|
|
|
Value*! c = cache.search(id); |
|
|
|
if (catch e = c) { |
|
|
|
if (catch e = c) { |
|
|
|
if (e != SearchResult.MISSING) { |
|
|
|
if (e != SearchResult.MISSING) { |
|
|
|
return e?; |
|
|
|
return e?; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// if the element is new (inserted) set the is_new flag |
|
|
|
// if the element is new (inserted) set the is_new flag |
|
|
|
if (is_new) *is_new = true; |
|
|
|
if (is_new) *is_new = true; |
|
|
|
return cache.insert_new(g, id); |
|
|
|
return cache.insert_new(g, id); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
if (is_new) *is_new = false; |
|
|
|
if (is_new) *is_new = false; |
|
|
|
return c; |
|
|
|
return c; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|