restorable: Bug fix: wrong topological sort (#359)

This commit is contained in:
Hajime Hoshi 2017-06-03 02:41:37 +09:00
parent 91b5d985fe
commit ad1f1263f7
2 changed files with 44 additions and 28 deletions

View File

@ -228,6 +228,14 @@ func (p *Image) dependsOn(target *Image) bool {
return false return false
} }
func (p *Image) dependingImages() map[*Image]struct{} {
r := map[*Image]struct{}{}
for _, c := range p.drawImageHistory {
r[c.image] = struct{}{}
}
return r
}
func (p *Image) hasDependency() bool { func (p *Image) hasDependency() bool {
if p.stale { if p.stale {
return false return false
@ -275,7 +283,7 @@ func (p *Image) restore() error {
gimg.Fill(p.baseColor) gimg.Fill(p.baseColor)
} }
for _, c := range p.drawImageHistory { for _, c := range p.drawImageHistory {
// c.image.image must be already restored. // All dependencies must be already resolved.
if c.image.hasDependency() { if c.image.hasDependency() {
panic("not reached") panic("not reached")
} }

View File

@ -93,37 +93,45 @@ func (i *images) restore() error {
// Let's do topological sort based on dependencies of drawing history. // Let's do topological sort based on dependencies of drawing history.
// There should not be a loop since cyclic drawing makes images stale. // There should not be a loop since cyclic drawing makes images stale.
current := map[*Image]struct{}{} type edge struct {
toBeDetermined := map[*Image]struct{}{} source *Image
target *Image
}
images := map[*Image]struct{}{}
for i := range i.images {
images[i] = struct{}{}
}
edges := map[edge]struct{}{}
for t := range images {
for s := range t.dependingImages() {
edges[edge{source: s, target: t}] = struct{}{}
}
}
sorted := []*Image{} sorted := []*Image{}
for img := range i.images { for len(images) > 0 {
if img.hasDependency() { // current repesents images that have no incoming edges.
toBeDetermined[img] = struct{}{} current := map[*Image]struct{}{}
continue for i := range images {
current[i] = struct{}{}
} }
current[img] = struct{}{} for e := range edges {
sorted = append(sorted, img) if _, ok := current[e.target]; ok {
} delete(current, e.target)
// TODO: How to confirm that there is no loop?
for len(current) > 0 {
next := map[*Image]struct{}{}
// TODO: This is inefficient. Get all edges from the source first.
// (*Image).childImages?
for source := range current {
for target := range toBeDetermined {
if target.dependsOn(source) {
next[target] = struct{}{}
} }
} }
for i := range current {
delete(images, i)
sorted = append(sorted, i)
} }
for img := range next { removed := []edge{}
sorted = append(sorted, img) for e := range edges {
delete(toBeDetermined, img) if _, ok := current[e.source]; ok {
removed = append(removed, e)
} }
current = next
} }
if len(toBeDetermined) > 0 { for _, e := range removed {
panic("not reached") delete(edges, e)
}
} }
for _, img := range sorted { for _, img := range sorted {
if err := img.restore(); err != nil { if err := img.restore(); err != nil {