mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-19 04:12:22 -07:00
core:container/topological_sort
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
// The following is a generic O(V+E) topological sorter implementation.
|
||||
// This is the fastest known method for topological sorting and Odin's
|
||||
// map type is being used to accelerate lookups.
|
||||
package container_topological_sort
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:runtime"
|
||||
_ :: intrinsics
|
||||
_ :: runtime
|
||||
|
||||
|
||||
Relations :: struct($K: typeid) where intrinsics.type_is_valid_map_key(K) {
|
||||
dependents: map[K]bool,
|
||||
dependencies: int,
|
||||
}
|
||||
|
||||
Sorter :: struct(K: typeid) where intrinsics.type_is_valid_map_key(K) {
|
||||
relations: map[K]Relations(K),
|
||||
dependents_allocator: runtime.Allocator,
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
make_relations :: proc(sorter: ^$S/Sorter($K)) -> (r: Relations(K)) {
|
||||
r.dependents.allocator = sorter.dependents_allocator
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
init :: proc(sorter: ^$S/Sorter($K)) {
|
||||
sorter.relations = make(map[K]Relations(K))
|
||||
sorter.dependents_allocator = context.allocator
|
||||
}
|
||||
|
||||
destroy :: proc(sorter: ^$S/Sorter($K)) {
|
||||
for _, v in &sorter.relations {
|
||||
delete(v.dependents)
|
||||
}
|
||||
delete(sorter.relations)
|
||||
}
|
||||
|
||||
add_key :: proc(sorter: ^$S/Sorter($K), key: K) -> bool {
|
||||
if key in sorter.relations {
|
||||
return false
|
||||
}
|
||||
sorter.relations[key] = make_relations(sorter)
|
||||
return true
|
||||
}
|
||||
|
||||
add_dependency :: proc(sorter: ^$S/Sorter($K), key, dependency: K) -> bool {
|
||||
if key == dependency {
|
||||
return false
|
||||
}
|
||||
|
||||
find := &sorter.relations[dependency]
|
||||
if find == nil {
|
||||
find = map_insert(&sorter.relations, dependency, make_relations(sorter))
|
||||
}
|
||||
|
||||
if find.dependents[key] {
|
||||
return true
|
||||
}
|
||||
find.dependents[key] = true
|
||||
|
||||
find = &sorter.relations[key]
|
||||
if find == nil {
|
||||
find = map_insert(&sorter.relations, key, make_relations(sorter))
|
||||
}
|
||||
|
||||
find.dependencies += 1
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
sort :: proc(sorter: ^$S/Sorter($K)) -> (sorted, cycled: [dynamic]K) {
|
||||
relations := &sorter.relations
|
||||
|
||||
for k, v in relations {
|
||||
if v.dependencies == 0 {
|
||||
append(&sorted, k)
|
||||
}
|
||||
}
|
||||
|
||||
for root in &sorted do for k, _ in relations[root].dependents {
|
||||
relation := &relations[k]
|
||||
relation.dependencies -= 1
|
||||
if relation.dependencies == 0 {
|
||||
append(&sorted, k)
|
||||
}
|
||||
}
|
||||
|
||||
for k, v in relations {
|
||||
if v.dependencies != 0 {
|
||||
append(&cycled, k)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user