Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package main
- import (
- "fmt"
- "log"
- )
- func main() {
- /*
- c = a - b
- x = c + d
- a = 5
- b = 3
- d = -2
- c, x = ? (c = 2, x = 0)
- */
- a := Field{
- Name: "a",
- Expression: NewExpression(),
- }
- b := Field{
- Name: "b",
- Expression: NewExpression(),
- }
- d := Field{
- Name: "d",
- Expression: NewExpression(),
- }
- c := Field{
- Name: "c",
- Expression: NewExpression().Add(a).Sub(b),
- // (a - b)
- }
- x := Field{
- Name: "x",
- Expression: NewExpression().Add(c).Add(d),
- // (c + d)
- }
- y := Field{
- Name: "y",
- Expression: NewExpression().Add(x).Add(a).Add(b),
- // (x + a + b)
- }
- ctx := NewContext()
- ctx.Put(a, 5)
- ctx.Put(b, 3)
- ctx.Put(d, -1)
- ctx.Declare(c)
- ctx.Declare(y)
- ctx.Declare(x)
- res, err := ctx.Calc()
- if err != nil {
- panic(err)
- }
- if res[c] != 2 {
- panic(fmt.Sprintf("Wrong 'c' = %v", res[c]))
- }
- if res[x] != 1 {
- panic(fmt.Sprintf("Wrong 'x' = %v", res[x]))
- }
- if res[y] != 9 {
- panic(fmt.Sprintf("Wrong 'y' = %v", res[y]))
- }
- log.Print("Successful!")
- }
- type FieldValue struct {
- value float64
- calculated bool
- }
- type Context struct {
- fields map[Field]FieldValue
- dependencies map[Field][]Dependency
- }
- func NewContext() *Context{
- c := &Context{}
- c.fields = make(map[Field]FieldValue)
- c.dependencies = make(map[Field][]Dependency)
- return c
- }
- func (c Context) Put(f Field, val float64) {
- c.fields[f] = FieldValue{
- value: val,
- calculated: true,
- }
- c.dependencies[f] = nil
- }
- func (c Context) Declare(f Field) {
- c.fields[f] = FieldValue{
- calculated: false,
- }
- c.dependencies[f] = f.Expression.dependencies
- }
- func (c Context) Calc() (map[Field]float64, error) {
- for {
- haveUncalculated := false
- for f, v := range c.fields {
- if v.calculated {
- continue
- }
- if c.readyToCalculate(f) {
- c.fields[f] = FieldValue{
- value: c.calcField(f),
- calculated: true,
- }
- } else {
- haveUncalculated = true
- }
- }
- if !haveUncalculated {
- break
- }
- }
- res := make(map[Field]float64)
- for f, v := range c.fields {
- res[f] = v.value
- }
- return res, nil
- }
- func (c Context) readyToCalculate(f Field) bool {
- deps, found := c.dependencies[f]
- if !found {
- return true
- }
- for _, d := range deps {
- if !c.fields[d.field].calculated {
- return false
- }
- }
- return true
- }
- func (c Context) calcField(f Field) float64 {
- deps, found := c.dependencies[f]
- if !found {
- panic(fmt.Sprintf("Empty deps"))
- }
- var res float64
- for _, d := range deps {
- switch d.operation {
- case OperationAdd:
- res += c.fields[d.field].value
- case OperationSub:
- res = res - c.fields[d.field].value
- default:
- //todo
- }
- }
- return res
- }
- //--------------------------------------------
- type Field struct {
- Name string
- Expression *Expression
- }
- //--------------------------------------------
- type Operation string
- const (
- OperationAdd Operation = "add"
- OperationSub Operation = "sub"
- )
- //--------------------------------------------
- type Dependency struct {
- field Field
- operation Operation
- }
- type Expression struct {
- dependencies []Dependency
- }
- func NewExpression() *Expression {
- return &Expression{}
- }
- func (e *Expression) Add(field Field) *Expression {
- d := Dependency{
- field: field,
- operation: OperationAdd,
- }
- e.dependencies = append(e.dependencies, d)
- return e
- }
- func (e *Expression) Sub(field Field) *Expression {
- d := Dependency{
- field: field,
- operation: OperationSub,
- }
- e.dependencies = append(e.dependencies, d)
- return e
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement