///|
/// Direct reference counts only; source_count does not measure retained size.
pub struct ReferencedObject {
object_id : UInt64
reference_count : Int
source_count : Int
present_in_heap : Bool
}
///|
/// Distinct source objects, unlike incoming(), which preserves every edge.
pub fn ReferenceIndex::referrer_ids(
self : ReferenceIndex,
id : UInt64,
offset? : Int = 0,
limit? : Int = 100,
) -> Array[UInt64] raise ParseError {
let unique : Map[UInt64, Bool] = Map([])
for edge in self.inbound.get(id).unwrap_or([]) {
unique[edge.source_id] = true
}
let ids = unique.keys().to_array()
ids.sort()
let end = page_end(offset, limit, ids.length())
ids[offset:end].to_owned()
}
///|
/// Ranks targets by distinct referring objects, then edge count, then ID.
/// Multiple array slots or fields in one source are not multiple sources.
pub fn ReferenceIndex::most_referenced(
self : ReferenceIndex,
limit? : Int = 20,
) -> Array[ReferencedObject] raise ParseError {
let end = page_end(0, limit, self.inbound.length())
if end == 0 {
return []
}
let result = []
for id, edges in self.inbound {
let sources : Map[UInt64, Bool] = Map([])
for edge in edges {
sources[edge.source_id] = true
}
result.push({
object_id: id,
reference_count: edges.length(),
source_count: sources.length(),
present_in_heap: self.known_nodes.contains(id),
})
}
result.sort_by((a, b) => {
let sources = b.source_count.compare(a.source_count)
if sources != 0 {
sources
} else {
let edges = b.reference_count.compare(a.reference_count)
if edges != 0 {
edges
} else {
a.object_id.compare(b.object_id)
}
}
})
result[0:end].to_owned()
}
///|
pub fn ReferencedObject::to_json(self : ReferencedObject) -> Json {
Json::object({
"object_id": json_id(self.object_id),
"reference_count": json_int(self.reference_count),
"source_count": json_int(self.source_count),
"present_in_heap": Json::boolean(self.present_in_heap),
})
}