Skip to content

Commit

Permalink
Automate memory management for Pigosat instances
Browse files Browse the repository at this point in the history
  • Loading branch information
wkschwartz committed Jan 28, 2014
1 parent feba6c3 commit 06b6f30
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 13 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@ Use
---

After completing the building and installation steps above, importation should
work as usual. Create a `Pigosat` object `p` and use its methods. Because of the
C-language PicoSAT component of PiGoSAT, you must explicitly free `p` when you
are done using `p`, and you will not be able to use `p` thereafter. The best
practice if you are using `p` all within one function is to use `defer`.
work as usual. Create a `Pigosat` object `p` and use its methods. Even though
PicoSAT is written in C, PiGoSAT manages memory for you using
`runtime.SetFinalizer`. (If you reset a `Pigosat` instance `p`'s finalizer, you
will have to call `p.Delete` explicitly, which is best done with `defer` right
after reseting the finalizer; most users will not need to worry about this.)

Designing your model is beyond the scope of this document, but Googling
"satisfiability problem", "conjunctive normal form", and "DIMACS" are good
Expand All @@ -65,7 +66,6 @@ package main
import "pigosat"
func main() {
p := pigosat.NewPigosat(0)
defer p.Delete()
p.AddClauses([][]int32{{1, 2}, {-2}})
status, solution := p.Solve()
// Now status should equal pigosat.Satisfiable and solution should be
Expand Down
13 changes: 9 additions & 4 deletions pigosat.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ package pigosat
// #include "picosat.h"
import "C"
import "fmt"
import "runtime"
import "sync"
import "time"

Expand Down Expand Up @@ -53,12 +54,16 @@ func NewPigosat(propagation_limit uint64) *Pigosat {
if propagation_limit > 0 {
C.picosat_set_propagation_limit(p, C.ulonglong(propagation_limit))
}
return &Pigosat{p: p, lock: new(sync.RWMutex)}
pgo := &Pigosat{p: p, lock: new(sync.RWMutex)}
runtime.SetFinalizer(pgo, (*Pigosat).Delete)
return pgo
}

// DelPigosat must be called on every Pigosat instance before each goes out of
// scope or the program ends, or else the program will leak memory. Once
// DelPigosat has been called on an instance, it cannot be used again.
// Delete may be called when you are done using a Pigosat instance, after which
// it cannot be used again. However, you only need to call this method if the
// instance's finalizer was reset using runtime.SetFinalizer (if you're not
// sure, it's always safe to call Delete again). Most users will not need this
// method.
func (p *Pigosat) Delete() {
if p == nil || p.p == nil {
return
Expand Down
4 changes: 0 additions & 4 deletions pigosat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ func TestFormulas(t *testing.T) {
p.AddClauses(ft.formula)
status, solution = p.Solve()
wasExpected(t, i, p, &ft, status, solution)
p.Delete()
}
}

Expand All @@ -159,11 +158,9 @@ func TestPropLimit(t *testing.T) {
t.Errorf("Propagation limit %d had no effect on formula 0",
limit)
}
p.Delete()
continue
}
wasExpected(t, 0, p, &ft, status, solution)
p.Delete()
}
}

Expand Down Expand Up @@ -202,7 +199,6 @@ func TestPicosatVersion(t *testing.T) {
// This is the example from the README.
func Example_readme() {
p := NewPigosat(0)
defer p.Delete()
p.AddClauses([][]int32{{1, 2}, {-2}})
fmt.Println("")
fmt.Printf("# variables == %d\n", p.Variables())
Expand Down

0 comments on commit 06b6f30

Please sign in to comment.