You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
1.8 KiB
101 lines
1.8 KiB
package pixelMenu
|
|
|
|
import (
|
|
"github.com/pkg/errors"
|
|
"gitlab.com/Pixdigit/uniqueID"
|
|
)
|
|
|
|
var ErrCircularDependency = errors.New("circular dependency while resolving")
|
|
|
|
var VarIDSpace = uniqueID.IDSpace{}
|
|
|
|
type Var struct {
|
|
id uniqueID.ID
|
|
isResolving bool
|
|
IsResolved bool
|
|
Value float64
|
|
evaluator func() float64
|
|
dependencies []Var
|
|
}
|
|
|
|
func Invariant(value float64) Var {
|
|
return Var{
|
|
VarIDSpace.NewID(),
|
|
false,
|
|
true,
|
|
value,
|
|
func() float64 { return value },
|
|
make([]Var, 0),
|
|
}
|
|
}
|
|
|
|
func NewVar() Var {
|
|
return Var{
|
|
VarIDSpace.NewID(),
|
|
false,
|
|
false,
|
|
0,
|
|
func() float64 { return 0 },
|
|
make([]Var, 0),
|
|
}
|
|
}
|
|
|
|
func Combine(p1, p2 Var, combinator func(float64, float64) float64) Var {
|
|
return Var{
|
|
VarIDSpace.NewID(),
|
|
false,
|
|
false,
|
|
0,
|
|
func() float64 { return combinator(p1.evaluator(), p2.evaluator()) },
|
|
[]Var{p1, p2},
|
|
}
|
|
}
|
|
|
|
func Add(p1, p2 Var) Var {
|
|
return Combine(p1, p2, func(arg1 float64, arg2 float64) float64 {
|
|
return arg1 + arg2
|
|
})
|
|
}
|
|
func Sub(p1, p2 Var) Var {
|
|
return Combine(p1, p2, func(arg1 float64, arg2 float64) float64 {
|
|
return arg1 - arg2
|
|
})
|
|
}
|
|
func Mul(p1, p2 Var) Var {
|
|
return Combine(p1, p2, func(arg1 float64, arg2 float64) float64 {
|
|
return arg1 * arg2
|
|
})
|
|
}
|
|
func Div(p1, p2 Var) Var {
|
|
return Combine(p1, p2, func(arg1 float64, arg2 float64) float64 {
|
|
return arg1 / arg2
|
|
})
|
|
}
|
|
|
|
func (p *Var) HasDependency(p2 Var) bool {
|
|
for _, dep := range p.dependencies {
|
|
if dep.id == p2.id {
|
|
return true
|
|
}
|
|
if dep.HasDependency(p2) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (p *Var) Resolve() error {
|
|
p.isResolving = true
|
|
defer func() { p.isResolving = false }()
|
|
//Assume user has done dependency check
|
|
for _, dep := range p.dependencies {
|
|
if !dep.IsResolved {
|
|
dep.Resolve()
|
|
}
|
|
}
|
|
|
|
p.Value = p.evaluator()
|
|
|
|
p.IsResolved = true
|
|
return nil
|
|
}
|
|
|