<commit_before>package logreg

import "testing"

func TestNewLogisticRegression(t *testing.T) {
	if lr := NewLogisticRegression(); lr == nil {
		t.Errorf("got nil linear regression")
	}
}

func TestInitialize(t *testing.T) {
	lr := NewLogisticRegression()
	lr.Initialize()

	if len(lr.Xn) != len(lr.Yn) {
		t.Errorf("got different size of vectors Xn Yn, wants same size")
	}

	if len(lr.Xn[0]) != len(lr.Wn) {
		t.Errorf("got different size of vectors Xn Wn, wants same size")
	}

	if len(lr.Xn) != lr.TrainingPoints {
		t.Errorf("got different size of vectors Xn and training points, wants same number")
	}

	for i := 0; i < len(lr.Xn); i++ {
		for j := 0; j < len(lr.Xn[0]); j++ {
			if lr.Xn[i][j] < lr.Interval.Min ||
				lr.Xn[i][j] > lr.Interval.Max {
				t.Errorf("got value of Xn[%d][%d] = %v, want it between %v and %v", i, j, lr.Xn[i][j], lr.Interval.Min, lr.Interval.Max)
			}
		}
	}

	for i := 0; i < len(lr.Yn); i++ {
		if lr.Yn[i] != float64(-1) && lr.Yn[i] != float64(1) {
			t.Errorf("got value of Yn[%v] = %v, want it equal to -1 or 1", i, lr.Yn[i])
		}
	}
}

func TestInitializeFromData(t *testing.T) {
	data := [][]float64{
		{1, 1, 1},
		{1, 1, 1},
		{1, 1, 1},
		{1, 1, 1},
		{1, 1, 1},
		{1, 1, 1},
	}

	lr := NewLogisticRegression()
	if err := lr.InitializeFromData(data); err != nil {
		t.Errorf("%v", err)
	}
	if len(lr.Xn) != len(data) || len(lr.Yn) != len(data) {
		t.Errorf("got difference in size of Xn or Yn and data")
	}

	if len(lr.Xn) != lr.TrainingPoints {
		t.Errorf("got difference in size of Xn or TrainingPoints and data")
	}

	if len(lr.Xn[0]) != len(lr.Wn) {
		t.Errorf("got different size of vectors Xn Wn, wants same size")
	}

	if len(lr.Xn[0]) != lr.VectorSize || len(data[0]) != lr.VectorSize {
		t.Errorf("got difference in size of Xn[0] or data[0] with VectorSize")
	}
}

func TestLearn(t *testing.T) {
	lr := NewLogisticRegression()
	data := [][]float64{
		{0.1, 1, 1},
		{0.2, 1, 1},
		{0.3, 1, 1},
		{1, 0.5, -1},
		{1, 0.6, -1},
		{1, 0.7, -1},
	}

	lr.InitializeFromData(data)
	lr.Learn()
	expectedWn := []float64{0.06586, -0.99194, 0.56851}
	if !equal(expectedWn, lr.Wn) {
		t.Errorf("Weight vector is not correct: got %v, want %v", lr.Wn, expectedWn)
	}
}

func TestGradient(t *testing.T) {
	tests := []struct {
		w    []float64
		y    float64
		wn   []float64
		want []float64
	}{
		{
			w:    []float64{0, 0, 0},
			y:    1,
			wn:   []float64{0, 0, 0, 0},
			want: []float64{-0.5, 0, 0, 0},
		},
		{
			w:    []float64{1, 0, 0},
			y:    1,
			wn:   []float64{0, 0, 0, 0},
			want: []float64{-0.5, -0.5, 0, 0},
		},
		{
			w:    []float64{1, 1, 0},
			y:    1,
			wn:   []float64{0, 0, 0, 0},
			want: []float64{-0.5, -0.5, -0.5, 0},
		},
		{
			w:    []float64{1, 1, 1},
			y:    1,
			wn:   []float64{0, 0, 0, 0},
			want: []float64{-0.5, -0.5, -0.5, -0.5},
		},
	}
	for i, tt := range tests {
		lr := NewLogisticRegression()
		lr.Wn = tt.wn
		got := lr.Gradient(tt.w, tt.y)
		if !equal(got, tt.want) {
			t.Errorf("test %i: got Gradient = %v, want %v", i, got, tt.want)
		}
	}
}

func TestUpdateWeights(t *testing.T) {
	tests := []struct {
		eta            float64
		w              []float64
		gradientVector []float64
		want           []float64
	}{
		{
			eta:            0.1,
			w:              []float64{1, 1, 1},
			gradientVector: []float64{1, 1, 1},
			want:           []float64{0.9, 0.9, 0.9},
		},
	}

	for i, tt := range tests {
		lr := NewLogisticRegression()
		lr.Eta = tt.eta
		lr.Wn = tt.w
		lr.UpdateWeights(tt.gradientVector)
		got := lr.Wn
		if !equal(got, tt.want) {
			t.Errorf("test %v: got Wn:%v, want %v", i, got, tt.want)
		}
	}
}

const epsilon float64 = 0.001

func equal(a, b []float64) bool {
	if len(a) != len(b) {
		return false
	}
	for i := range a {
		if (a[i] - b[i]) > epsilon {
			return false
		}
	}
	return true
}
<commit_msg>logreg - add tests to updateWeights<commit_after>package logreg

import "testing"

func TestNewLogisticRegression(t *testing.T) {
	if lr := NewLogisticRegression(); lr == nil {
		t.Errorf("got nil linear regression")
	}
}

func TestInitialize(t *testing.T) {
	lr := NewLogisticRegression()
	lr.Initialize()

	if len(lr.Xn) != len(lr.Yn) {
		t.Errorf("got different size of vectors Xn Yn, wants same size")
	}

	if len(lr.Xn[0]) != len(lr.Wn) {
		t.Errorf("got different size of vectors Xn Wn, wants same size")
	}

	if len(lr.Xn) != lr.TrainingPoints {
		t.Errorf("got different size of vectors Xn and training points, wants same number")
	}

	for i := 0; i < len(lr.Xn); i++ {
		for j := 0; j < len(lr.Xn[0]); j++ {
			if lr.Xn[i][j] < lr.Interval.Min ||
				lr.Xn[i][j] > lr.Interval.Max {
				t.Errorf("got value of Xn[%d][%d] = %v, want it between %v and %v", i, j, lr.Xn[i][j], lr.Interval.Min, lr.Interval.Max)
			}
		}
	}

	for i := 0; i < len(lr.Yn); i++ {
		if lr.Yn[i] != float64(-1) && lr.Yn[i] != float64(1) {
			t.Errorf("got value of Yn[%v] = %v, want it equal to -1 or 1", i, lr.Yn[i])
		}
	}
}

func TestInitializeFromData(t *testing.T) {
	data := [][]float64{
		{1, 1, 1},
		{1, 1, 1},
		{1, 1, 1},
		{1, 1, 1},
		{1, 1, 1},
		{1, 1, 1},
	}

	lr := NewLogisticRegression()
	if err := lr.InitializeFromData(data); err != nil {
		t.Errorf("%v", err)
	}
	if len(lr.Xn) != len(data) || len(lr.Yn) != len(data) {
		t.Errorf("got difference in size of Xn or Yn and data")
	}

	if len(lr.Xn) != lr.TrainingPoints {
		t.Errorf("got difference in size of Xn or TrainingPoints and data")
	}

	if len(lr.Xn[0]) != len(lr.Wn) {
		t.Errorf("got different size of vectors Xn Wn, wants same size")
	}

	if len(lr.Xn[0]) != lr.VectorSize || len(data[0]) != lr.VectorSize {
		t.Errorf("got difference in size of Xn[0] or data[0] with VectorSize")
	}
}

func TestLearn(t *testing.T) {
	lr := NewLogisticRegression()
	data := [][]float64{
		{0.1, 1, 1},
		{0.2, 1, 1},
		{0.3, 1, 1},
		{1, 0.5, -1},
		{1, 0.6, -1},
		{1, 0.7, -1},
	}

	lr.InitializeFromData(data)
	lr.Learn()
	expectedWn := []float64{0.06586, -0.99194, 0.56851}
	if !equal(expectedWn, lr.Wn) {
		t.Errorf("Weight vector is not correct: got %v, want %v", lr.Wn, expectedWn)
	}
}

func TestGradient(t *testing.T) {
	tests := []struct {
		w    []float64
		y    float64
		wn   []float64
		want []float64
	}{
		{
			w:    []float64{0, 0, 0},
			y:    1,
			wn:   []float64{0, 0, 0, 0},
			want: []float64{-0.5, 0, 0, 0},
		},
		{
			w:    []float64{1, 0, 0},
			y:    1,
			wn:   []float64{0, 0, 0, 0},
			want: []float64{-0.5, -0.5, 0, 0},
		},
		{
			w:    []float64{1, 1, 0},
			y:    1,
			wn:   []float64{0, 0, 0, 0},
			want: []float64{-0.5, -0.5, -0.5, 0},
		},
		{
			w:    []float64{1, 1, 1},
			y:    1,
			wn:   []float64{0, 0, 0, 0},
			want: []float64{-0.5, -0.5, -0.5, -0.5},
		},
	}
	for i, tt := range tests {
		lr := NewLogisticRegression()
		lr.Wn = tt.wn
		got := lr.Gradient(tt.w, tt.y)
		if !equal(got, tt.want) {
			t.Errorf("test %i: got Gradient = %v, want %v", i, got, tt.want)
		}
	}
}

func TestUpdateWeights(t *testing.T) {
	tests := []struct {
		eta            float64
		w              []float64
		gradientVector []float64
		want           []float64
	}{
		{
			eta:            0.1,
			w:              []float64{1, 1, 1},
			gradientVector: []float64{1, 1, 1},
			want:           []float64{0.9, 0.9, 0.9},
		},
		{
			eta:            0.5,
			w:              []float64{1, 1, 1},
			gradientVector: []float64{1, 1, 1},
			want:           []float64{0.5, 0.5, 0.5},
		},
		{
			eta:            0,
			w:              []float64{1, 1, 1},
			gradientVector: []float64{1, 1, 1},
			want:           []float64{1, 1, 1},
		},
		{
			eta:            0.1,
			w:              []float64{0, 0, 0},
			gradientVector: []float64{1, 1, 1},
			want:           []float64{0.1, 0.1, 0.1},
		},
		{
			eta:            0.1,
			w:              []float64{1, 1, 1},
			gradientVector: []float64{0, 0, 0},
			want:           []float64{1, 1, 1},
		},
	}

	for i, tt := range tests {
		lr := NewLogisticRegression()
		lr.Eta = tt.eta
		lr.Wn = tt.w
		lr.UpdateWeights(tt.gradientVector)
		got := lr.Wn
		if !equal(got, tt.want) {
			t.Errorf("test %v: got Wn:%v, want %v", i, got, tt.want)
		}
	}
}

const epsilon float64 = 0.001

func equal(a, b []float64) bool {
	if len(a) != len(b) {
		return false
	}
	for i := range a {
		if (a[i] - b[i]) > epsilon {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, Rob Thornton
// All rights reserved.
// This source code is governed by a Simplied BSD-License. Please see the
// LICENSE included in this distribution for a copy of the full license
// or, if one is not included, you may also find a copy at
// http://opensource.org/licenses/BSD-2-Clause

package comp

import (
	"fmt"
	"os"
	"reflect"
	"strconv"

	"github.com/rthornton128/calc/ast"
	"github.com/rthornton128/calc/parse"
	"github.com/rthornton128/calc/token"
)

type compiler struct {
	fp       *os.File
	fset     *token.FileSet
	errors   token.ErrorList
	offset   int
	curScope *ast.Scope
	topScope *ast.Scope
}

func CompileFile(fname, src string) {
	var c compiler
	fp, err := os.Create(fname + ".c")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer fp.Close()

	c.fset = token.NewFileSet()
	f := parse.ParseFile(c.fset.Add(fname, src), fname, src)
	if f == nil {
		os.Exit(1)
	}
	c.fp = fp
	c.compFile(f)

	if c.errors.Count() != 0 {
		c.errors.Print()
		os.Exit(1)
	}
}

/* Utility */

func (c *compiler) Error(pos token.Pos, args ...interface{}) {
	c.errors.Add(c.fset.Position(pos), args...)
}

func roundUp16(n int) int {
	if r := n % 16; r != 0 {
		return n + (16 - r)
	}
	return n
}

func (c *compiler) nextOffset() (offset int) {
	offset = c.offset
	c.offset += 4
	return
}

/* Scope */

func (c *compiler) openScope(s *ast.Scope) {
	c.curScope = s
}

func (c *compiler) closeScope() {
	c.curScope = c.curScope.Parent
}

/* Main Compiler */

func (c *compiler) compNode(node ast.Node) int {
	switch n := node.(type) {
	case *ast.AssignExpr:
		c.compAssignExpr(n)
	case *ast.BasicLit:
		c.compInt(n, "eax")
	case *ast.BinaryExpr:
		return c.compBinaryExpr(n)
	case *ast.CallExpr:
		return c.compCallExpr(n)
	case *ast.DeclExpr:
		return c.compDeclExpr(n)
	case *ast.ExprList:
		for i := range n.List {
			c.compNode(n.List[i])
		}
	case *ast.Ident:
		c.compIdent(n, "movl(ebp+%d, eax);\n")
	case *ast.IfExpr:
		c.compIfExpr(n)
	case *ast.VarExpr:
		c.compVarExpr(n)
	}
	return 0
}

func (c *compiler) compAssignExpr(a *ast.AssignExpr) {
	ob := c.curScope.Lookup(a.Name.Name)
	if ob == nil {
		c.Error(a.Name.NamePos, "can't assign value to undeclared variable '",
			a.Name.Name, "'")
		return
	}
	//fmt.Fprintf(c.fp, "setl(%d, ebp+%d);\n",
	// TODO: yikes! no type checking?!
	ob.Value = a.Value
	switch n := ob.Value.(type) {
	case *ast.BasicLit:
		c.compInt(n, fmt.Sprintf("ebp+%d", ob.Offset))
	case *ast.BinaryExpr:
		c.compBinaryExpr(n)
		fmt.Fprintf(c.fp, "movl(eax, ebp+%d);\n", ob.Offset)
	case *ast.CallExpr:
		c.compCallExpr(n)
		fmt.Fprintf(c.fp, "movl(eax, ebp+%d);\n", ob.Offset)
	case *ast.Ident:
		c.compIdent(n, fmt.Sprintf("movl(ebp+%%d, ebp+%d);\n", ob.Offset))
	}
}

func (c *compiler) compBinaryExpr(b *ast.BinaryExpr) int {
	switch n := b.List[0].(type) {
	case *ast.BasicLit:
		c.compInt(n, "eax")
	case *ast.BinaryExpr:
		c.compBinaryExpr(n)
	case *ast.CallExpr:
		c.compCallExpr(n)
	case *ast.Ident:
		c.compIdent(n, "movl(ebp+%d, eax);\n")
	}

	for _, node := range b.List[1:] {
		switch n := node.(type) {
		case *ast.BasicLit:
			c.compInt(n, "edx")
		case *ast.BinaryExpr:
			fmt.Fprintln(c.fp, "pushl(eax);")
			c.compBinaryExpr(n)
			fmt.Fprintln(c.fp, "movl(eax, edx);")
			fmt.Fprintln(c.fp, "popl(eax);")
		case *ast.CallExpr:
			fmt.Fprintln(c.fp, "pushl(eax);")
			c.compCallExpr(n)
			fmt.Fprintln(c.fp, "movl(eax, edx);")
			fmt.Fprintln(c.fp, "popl(eax);")
		case *ast.Ident:
			c.compIdent(n, "movl(ebp+%d, edx);\n")
		}
		switch b.Op {
		case token.ADD:
			fmt.Fprintln(c.fp, "addl(edx, eax);")
		case token.SUB:
			fmt.Fprintln(c.fp, "subl(edx, eax);")
		case token.MUL:
			fmt.Fprintln(c.fp, "mull(edx, eax);")
		case token.QUO:
			fmt.Fprintln(c.fp, "divl(edx, eax);")
		case token.REM:
			fmt.Fprintln(c.fp, "reml(edx, eax);")
		case token.AND:
			fmt.Fprintln(c.fp, "andl(eax, edx);")
		case token.EQL:
			fmt.Fprintln(c.fp, "eql(eax, edx);")
		case token.GTE:
			fmt.Fprintln(c.fp, "gel(eax, edx);")
		case token.GTT:
			fmt.Fprintln(c.fp, "gtl(eax, edx);")
		case token.LST:
			fmt.Fprintln(c.fp, "ltl(eax, edx);")
		case token.LTE:
			fmt.Fprintln(c.fp, "lel(eax, edx);")
		case token.NEQ:
			fmt.Fprintln(c.fp, "nel(eax, edx);")
		case token.OR:
			fmt.Fprintln(c.fp, "orl(eax, edx);")
		}
	}

	return 0
}

func (c *compiler) compCallExpr(e *ast.CallExpr) int {
	offset := 4

	ob := c.curScope.Lookup(e.Name.Name)
	switch {
	case ob == nil:
		c.Error(e.Name.NamePos, "call to undeclared function '", e.Name.Name, "'")
	case ob.Kind != ast.Decl:
		c.Error(e.Name.NamePos, "may not call object that is not a function")
	}

	for _, v := range e.Args {
		switch n := v.(type) {
		case *ast.BasicLit:
			c.compInt(n, fmt.Sprintf("esp+%d", offset))
		default:
			c.compNode(n)
			fmt.Fprintf(c.fp, "movl(eax, esp+%d);\n", offset)
		}
		offset += 4
	}
	fmt.Fprintf(c.fp, "_%s();\n", e.Name.Name)
	return 0
}

func (c *compiler) compDeclExpr(d *ast.DeclExpr) int {
	c.openScope(d.Scope)
	c.compScopeDecls()

	last := c.offset
	c.offset = 0
	for _, p := range d.Params {
		ob := c.curScope.Lookup(p.Name)
		ob.Offset = c.nextOffset()
	}
	x := c.countVars(d)
	fmt.Fprintf(c.fp, "void _%s(void) {\n", d.Name.Name)

	if x > 0 {
		fmt.Fprintf(c.fp, "enter(%d);\n", roundUp16(x))
		c.compNode(d.Body)
		fmt.Fprintln(c.fp, "leave();")
	} else {
		c.compNode(d.Body)
	}

	fmt.Fprintln(c.fp, "}")
	c.offset = last
	c.closeScope()
	return 0
}

func (c *compiler) compFile(f *ast.File) {
	fmt.Fprintln(c.fp, "#include <stdio.h>")
	fmt.Fprintln(c.fp, "#include <runtime.h>")
	c.topScope = f.Scope
	c.curScope = c.topScope
	ob := c.curScope.Lookup("main")
	switch {
	case ob == nil:
		c.Error(token.NoPos, "no entry point, function 'main' not found")
	case ob.Kind != ast.Decl:
		c.Error(ob.NamePos, "no entry point, 'main' is not a function")
	case ob.Type == nil:
		c.Error(ob.NamePos, "'main' must be of type int but was declared as "+
			"void")
	case ob.Type.Name != "int":
		c.Error(ob.Type.NamePos, "'main' must be of type but declared as ",
			ob.Type.Name)
	}
	c.compScopeDecls()
	fmt.Fprintln(c.fp, "int main(void) {")
	fmt.Fprintln(c.fp, "stack_init();")
	fmt.Fprintln(c.fp, "_main();")
	fmt.Fprintln(c.fp, "printf(\"%d\\n\", *(int32_t *)eax);")
	fmt.Fprintln(c.fp, "stack_end();")
	fmt.Fprintln(c.fp, "return *(int32_t*) eax;")
	fmt.Fprintln(c.fp, "}")
}

func (c *compiler) compIdent(n *ast.Ident, format string) {
	ob := c.curScope.Lookup(n.Name)
	if ob == nil {
		panic("no offset for identifier")
	}
	fmt.Fprintf(c.fp, format, ob.Offset)
}

func (c *compiler) compIfExpr(n *ast.IfExpr) {
	switch e := n.Cond.(type) {
	case *ast.BasicLit:
		c.compInt(e, "eax")
	case *ast.BinaryExpr:
		c.compBinaryExpr(e)
	}
	fmt.Fprintln(c.fp, "if (*(int32_t *)ecx == 1) {")
	c.openScope(n.Scope)
	c.compNode(n.Then)
	if n.Type != nil {
		fmt.Fprintln(c.fp, "leave();")
		fmt.Fprintln(c.fp, "return;")
	}
	if n.Else != nil && !reflect.ValueOf(n.Else).IsNil() {
		fmt.Fprintln(c.fp, "} else {")
		c.compNode(n.Else)
		if n.Type != nil {
			fmt.Fprintln(c.fp, "leave();")
			fmt.Fprintln(c.fp, "return;")
		}
	}
	c.closeScope()
	fmt.Fprintln(c.fp, "}")
}

func (c *compiler) compInt(n *ast.BasicLit, reg string) {
	i, err := strconv.Atoi(n.Lit)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Fprintf(c.fp, "setl(%d, %s);\n", i, reg)
}

func (c *compiler) compScopeDecls() {
	for k, v := range c.curScope.Table {
		if v.Kind == ast.Decl {
			fmt.Fprintf(c.fp, "void _%s(void);\n", k)
			defer c.compNode(v.Value)
		}
	}
}

func (c *compiler) compVarExpr(v *ast.VarExpr) {
	ob := c.curScope.Lookup(v.Name.Name)
	ob.Offset = c.nextOffset()
	// TODO: value + infer type + check type
	if ob.Value != nil {
		switch n := ob.Value.(type) {
		case *ast.BasicLit:
			c.compInt(n, fmt.Sprintf("ebp+%d", ob.Offset))
		case *ast.BinaryExpr:
			c.compBinaryExpr(n)
			fmt.Fprintf(c.fp, "movl(eax, ebp+%d);\n", ob.Offset)
		case *ast.CallExpr:
			c.compCallExpr(n)
			fmt.Fprintf(c.fp, "movl(eax, ebp+%d);\n", ob.Offset)
		case *ast.Ident:
			c.compIdent(n, fmt.Sprintf("movl(ebp+%%d, ebp+%d);\n", ob.Offset))
		}
	}
}

func (c *compiler) countVars(n ast.Node) (x int) {
	if n != nil && !reflect.ValueOf(n).IsNil() {
		switch e := n.(type) {
		case *ast.DeclExpr:
			x = len(e.Params)
			x += c.countVars(e.Body)
		case *ast.IfExpr:
			x = c.countVars(e.Then)
			x = c.countVars(e.Else)
		case *ast.ExprList:
			for _, v := range e.List {
				x += c.countVars(v)
			}
		case *ast.VarExpr:
			x = 1
		}
	}
	return
}
<commit_msg>update varexpr to match parsing and spec and remove line of unused code<commit_after>// Copyright (c) 2014, Rob Thornton
// All rights reserved.
// This source code is governed by a Simplied BSD-License. Please see the
// LICENSE included in this distribution for a copy of the full license
// or, if one is not included, you may also find a copy at
// http://opensource.org/licenses/BSD-2-Clause

package comp

import (
	"fmt"
	"os"
	"reflect"
	"strconv"

	"github.com/rthornton128/calc/ast"
	"github.com/rthornton128/calc/parse"
	"github.com/rthornton128/calc/token"
)

type compiler struct {
	fp       *os.File
	fset     *token.FileSet
	errors   token.ErrorList
	offset   int
	curScope *ast.Scope
	topScope *ast.Scope
}

func CompileFile(fname, src string) {
	var c compiler
	fp, err := os.Create(fname + ".c")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer fp.Close()

	c.fset = token.NewFileSet()
	f := parse.ParseFile(c.fset.Add(fname, src), fname, src)
	if f == nil {
		os.Exit(1)
	}
	c.fp = fp
	c.compFile(f)

	if c.errors.Count() != 0 {
		c.errors.Print()
		os.Exit(1)
	}
}

/* Utility */

func (c *compiler) Error(pos token.Pos, args ...interface{}) {
	c.errors.Add(c.fset.Position(pos), args...)
}

func roundUp16(n int) int {
	if r := n % 16; r != 0 {
		return n + (16 - r)
	}
	return n
}

func (c *compiler) nextOffset() (offset int) {
	offset = c.offset
	c.offset += 4
	return
}

/* Scope */

func (c *compiler) openScope(s *ast.Scope) {
	c.curScope = s
}

func (c *compiler) closeScope() {
	c.curScope = c.curScope.Parent
}

/* Main Compiler */

func (c *compiler) compNode(node ast.Node) int {
	switch n := node.(type) {
	case *ast.AssignExpr:
		c.compAssignExpr(n)
	case *ast.BasicLit:
		c.compInt(n, "eax")
	case *ast.BinaryExpr:
		return c.compBinaryExpr(n)
	case *ast.CallExpr:
		return c.compCallExpr(n)
	case *ast.DeclExpr:
		return c.compDeclExpr(n)
	case *ast.ExprList:
		for i := range n.List {
			c.compNode(n.List[i])
		}
	case *ast.Ident:
		c.compIdent(n, "movl(ebp+%d, eax);\n")
	case *ast.IfExpr:
		c.compIfExpr(n)
	case *ast.VarExpr:
		c.compVarExpr(n)
	}
	return 0
}

func (c *compiler) compAssignExpr(a *ast.AssignExpr) {
	ob := c.curScope.Lookup(a.Name.Name)
	if ob == nil {
		c.Error(a.Name.NamePos, "can't assign value to undeclared variable '",
			a.Name.Name, "'")
		return
	}
	// TODO: yikes! no type checking?!
	ob.Value = a.Value
	switch n := ob.Value.(type) {
	case *ast.BasicLit:
		c.compInt(n, fmt.Sprintf("ebp+%d", ob.Offset))
	case *ast.BinaryExpr:
		c.compBinaryExpr(n)
		fmt.Fprintf(c.fp, "movl(eax, ebp+%d);\n", ob.Offset)
	case *ast.CallExpr:
		c.compCallExpr(n)
		fmt.Fprintf(c.fp, "movl(eax, ebp+%d);\n", ob.Offset)
	case *ast.Ident:
		c.compIdent(n, fmt.Sprintf("movl(ebp+%%d, ebp+%d);\n", ob.Offset))
	}
}

func (c *compiler) compBinaryExpr(b *ast.BinaryExpr) int {
	switch n := b.List[0].(type) {
	case *ast.BasicLit:
		c.compInt(n, "eax")
	case *ast.BinaryExpr:
		c.compBinaryExpr(n)
	case *ast.CallExpr:
		c.compCallExpr(n)
	case *ast.Ident:
		c.compIdent(n, "movl(ebp+%d, eax);\n")
	}

	for _, node := range b.List[1:] {
		switch n := node.(type) {
		case *ast.BasicLit:
			c.compInt(n, "edx")
		case *ast.BinaryExpr:
			fmt.Fprintln(c.fp, "pushl(eax);")
			c.compBinaryExpr(n)
			fmt.Fprintln(c.fp, "movl(eax, edx);")
			fmt.Fprintln(c.fp, "popl(eax);")
		case *ast.CallExpr:
			fmt.Fprintln(c.fp, "pushl(eax);")
			c.compCallExpr(n)
			fmt.Fprintln(c.fp, "movl(eax, edx);")
			fmt.Fprintln(c.fp, "popl(eax);")
		case *ast.Ident:
			c.compIdent(n, "movl(ebp+%d, edx);\n")
		}
		switch b.Op {
		case token.ADD:
			fmt.Fprintln(c.fp, "addl(edx, eax);")
		case token.SUB:
			fmt.Fprintln(c.fp, "subl(edx, eax);")
		case token.MUL:
			fmt.Fprintln(c.fp, "mull(edx, eax);")
		case token.QUO:
			fmt.Fprintln(c.fp, "divl(edx, eax);")
		case token.REM:
			fmt.Fprintln(c.fp, "reml(edx, eax);")
		case token.AND:
			fmt.Fprintln(c.fp, "andl(eax, edx);")
		case token.EQL:
			fmt.Fprintln(c.fp, "eql(eax, edx);")
		case token.GTE:
			fmt.Fprintln(c.fp, "gel(eax, edx);")
		case token.GTT:
			fmt.Fprintln(c.fp, "gtl(eax, edx);")
		case token.LST:
			fmt.Fprintln(c.fp, "ltl(eax, edx);")
		case token.LTE:
			fmt.Fprintln(c.fp, "lel(eax, edx);")
		case token.NEQ:
			fmt.Fprintln(c.fp, "nel(eax, edx);")
		case token.OR:
			fmt.Fprintln(c.fp, "orl(eax, edx);")
		}
	}

	return 0
}

func (c *compiler) compCallExpr(e *ast.CallExpr) int {
	offset := 4

	ob := c.curScope.Lookup(e.Name.Name)
	switch {
	case ob == nil:
		c.Error(e.Name.NamePos, "call to undeclared function '", e.Name.Name, "'")
	case ob.Kind != ast.Decl:
		c.Error(e.Name.NamePos, "may not call object that is not a function")
	}

	for _, v := range e.Args {
		switch n := v.(type) {
		case *ast.BasicLit:
			c.compInt(n, fmt.Sprintf("esp+%d", offset))
		default:
			c.compNode(n)
			fmt.Fprintf(c.fp, "movl(eax, esp+%d);\n", offset)
		}
		offset += 4
	}
	fmt.Fprintf(c.fp, "_%s();\n", e.Name.Name)
	return 0
}

func (c *compiler) compDeclExpr(d *ast.DeclExpr) int {
	c.openScope(d.Scope)
	c.compScopeDecls()

	last := c.offset
	c.offset = 0
	for _, p := range d.Params {
		ob := c.curScope.Lookup(p.Name)
		ob.Offset = c.nextOffset()
	}
	x := c.countVars(d)
	fmt.Fprintf(c.fp, "void _%s(void) {\n", d.Name.Name)

	if x > 0 {
		fmt.Fprintf(c.fp, "enter(%d);\n", roundUp16(x))
		c.compNode(d.Body)
		fmt.Fprintln(c.fp, "leave();")
	} else {
		c.compNode(d.Body)
	}

	fmt.Fprintln(c.fp, "}")
	c.offset = last
	c.closeScope()
	return 0
}

func (c *compiler) compFile(f *ast.File) {
	fmt.Fprintln(c.fp, "#include <stdio.h>")
	fmt.Fprintln(c.fp, "#include <runtime.h>")
	c.topScope = f.Scope
	c.curScope = c.topScope
	ob := c.curScope.Lookup("main")
	switch {
	case ob == nil:
		c.Error(token.NoPos, "no entry point, function 'main' not found")
	case ob.Kind != ast.Decl:
		c.Error(ob.NamePos, "no entry point, 'main' is not a function")
	case ob.Type == nil:
		c.Error(ob.NamePos, "'main' must be of type int but was declared as "+
			"void")
	case ob.Type.Name != "int":
		c.Error(ob.Type.NamePos, "'main' must be of type but declared as ",
			ob.Type.Name)
	}
	c.compScopeDecls()
	fmt.Fprintln(c.fp, "int main(void) {")
	fmt.Fprintln(c.fp, "stack_init();")
	fmt.Fprintln(c.fp, "_main();")
	fmt.Fprintln(c.fp, "printf(\"%d\\n\", *(int32_t *)eax);")
	fmt.Fprintln(c.fp, "stack_end();")
	fmt.Fprintln(c.fp, "return *(int32_t*) eax;")
	fmt.Fprintln(c.fp, "}")
}

func (c *compiler) compIdent(n *ast.Ident, format string) {
	ob := c.curScope.Lookup(n.Name)
	if ob == nil {
		panic("no offset for identifier")
	}
	fmt.Fprintf(c.fp, format, ob.Offset)
}

func (c *compiler) compIfExpr(n *ast.IfExpr) {
	switch e := n.Cond.(type) {
	case *ast.BasicLit:
		c.compInt(e, "eax")
	case *ast.BinaryExpr:
		c.compBinaryExpr(e)
	}
	fmt.Fprintln(c.fp, "if (*(int32_t *)ecx == 1) {")
	c.openScope(n.Scope)
	c.compNode(n.Then)
	if n.Type != nil {
		fmt.Fprintln(c.fp, "leave();")
		fmt.Fprintln(c.fp, "return;")
	}
	if n.Else != nil && !reflect.ValueOf(n.Else).IsNil() {
		fmt.Fprintln(c.fp, "} else {")
		c.compNode(n.Else)
		if n.Type != nil {
			fmt.Fprintln(c.fp, "leave();")
			fmt.Fprintln(c.fp, "return;")
		}
	}
	c.closeScope()
	fmt.Fprintln(c.fp, "}")
}

func (c *compiler) compInt(n *ast.BasicLit, reg string) {
	i, err := strconv.Atoi(n.Lit)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Fprintf(c.fp, "setl(%d, %s);\n", i, reg)
}

func (c *compiler) compScopeDecls() {
	for k, v := range c.curScope.Table {
		if v.Kind == ast.Decl {
			fmt.Fprintf(c.fp, "void _%s(void);\n", k)
			defer c.compNode(v.Value)
		}
	}
}

func (c *compiler) compVarExpr(v *ast.VarExpr) {
	ob := c.curScope.Lookup(v.Name.Name)
	ob.Offset = c.nextOffset()
	// TODO: value + infer type + check type
	if ob.Value != nil && !reflect.ValueOf(ob.Value).IsNil() {
		if val, ok := ob.Value.(*ast.AssignExpr); ok {
			c.compAssignExpr(val)
			return
		}
		panic("parsing error occured, object's Value is not an assignment")
	}
}

func (c *compiler) countVars(n ast.Node) (x int) {
	if n != nil && !reflect.ValueOf(n).IsNil() {
		switch e := n.(type) {
		case *ast.DeclExpr:
			x = len(e.Params)
			x += c.countVars(e.Body)
		case *ast.IfExpr:
			x = c.countVars(e.Then)
			x = c.countVars(e.Else)
		case *ast.ExprList:
			for _, v := range e.List {
				x += c.countVars(v)
			}
		case *ast.VarExpr:
			x = 1
		}
	}
	return
}
<|endoftext|>


<commit_before>package cast

func Complex64(v interface{}) (complex64, error) {

	switch value := v.(type) {
	case complex64:
		return complex64(value), nil
	case float32:
		return complex(float32(value), 0), nil
	case uint8:
		return complex(float32(value), 0), nil
	case uint16:
		return complex(float32(value), 0), nil
	case int8:
		return complex(float32(value), 0), nil
	case int16:
		return complex(float32(value), 0), nil
	case complex64er:
		return value.Complex64()
	default:
		return 0, internalCannotCastComplainer{expectedType:"complex64", actualType:typeof(value)}
	}
}

// MustComplex64 is like Complex64, expect panic()s on an error.
func MustComplex64(v interface{}) complex64 {

	x, err := Complex64(v)
	if nil != err {
		panic(err)
	}

	return x
}

type complex64er interface {
	Complex64() (complex64, error)
}
<commit_msg>updated docs<commit_after>package cast

// Complex64 will return a complex64 when `v` is of type complex64, float32, uint8, uint16, int8, int16, or has a method:
//
//	type interface {
//		Complex64() (complex64, error)
//	}
//
// Else it will return an error.
//
// When float32, uint8, uint16, int8, int16, are converted to a complex64, their value goes into the "real" component
// of the conplex number.
func Complex64(v interface{}) (complex64, error) {

	switch value := v.(type) {
	case complex64:
		return complex64(value), nil
	case float32:
		return complex(float32(value), 0), nil
	case uint8:
		return complex(float32(value), 0), nil
	case uint16:
		return complex(float32(value), 0), nil
	case int8:
		return complex(float32(value), 0), nil
	case int16:
		return complex(float32(value), 0), nil
	case complex64er:
		return value.Complex64()
	default:
		return 0, internalCannotCastComplainer{expectedType:"complex64", actualType:typeof(value)}
	}
}

// MustComplex64 is like Complex64, expect panic()s on an error.
func MustComplex64(v interface{}) complex64 {

	x, err := Complex64(v)
	if nil != err {
		panic(err)
	}

	return x
}

type complex64er interface {
	Complex64() (complex64, error)
}
<|endoftext|>


<commit_before>package ltick

import (
	"context"
	"reflect"
	"strings"

	"github.com/fatih/structs"
	"github.com/juju/errors"
	"github.com/ltick/tick-framework/config"
	"github.com/ltick/tick-framework/database"
	"github.com/ltick/tick-framework/filesystem"
	"github.com/ltick/tick-framework/kvstore"
	"github.com/ltick/tick-framework/logger"
	"github.com/ltick/tick-framework/queue"
	"github.com/ltick/tick-framework/session"
	"github.com/ltick/tick-framework/utility"
)

var (
	errComponentExists              = "ltick: component '%s' exists"
	errComponentNotExists           = "ltick: component '%s' not exists"
	errRegisterComponent            = "ltick: register component '%s' error"
	errUnregisterComponent          = "ltick: unregister component '%s' error"
	errInjectComponent              = "ltick: inject component '%s' field '%s' error"
	errInjectComponentTo            = "ltick: inject component '%s' field '%s' error"
	errUseComponent                 = "ltick: use component '%s' error"
	errValueExists                  = "ltick: value '%s' exists"
	errValueNotExists               = "ltick: value '%s' not exists"
	errConfigureComponentFileConfig = "ltick: configure component '%s' file config  error"
)

func (r *Registry) GetComponentMap() map[string]interface{} {
	return r.ComponentMap
}

type ComponentInterface interface {
	Initiate(ctx context.Context) (context.Context, error)
	OnStartup(ctx context.Context) (context.Context, error)
	OnShutdown(ctx context.Context) (context.Context, error)
}

type Components []*Component

func (cs Components) Get(name string) *Component {
	for _, c := range cs {
		canonicalName := strings.ToUpper(name[0:1]) + name[1:]
		if canonicalName == c.Name {
			return c
		}
	}
	return nil
}

type Component struct {
	Name          string
	Component     ComponentInterface
	ConfigurePath string
	Dependencies  []*Component
}

var (
	OptionalComponents = Components{
		&Component{Name: "Log", Component: &log.Logger{}, ConfigurePath: "components.log"},
		&Component{Name: "Database", Component: &database.Database{}, ConfigurePath: "components.database"},
		&Component{Name: "Kvstore", Component: &kvstore.Kvstore{}, ConfigurePath: "components.kvstore"},
		&Component{Name: "Queue", Component: &queue.Queue{}, ConfigurePath: "components.queue"},
		&Component{Name: "Filesystem", Component: &filesystem.Filesystem{}, ConfigurePath: "components.filesystem"},
		&Component{Name: "Session", Component: &session.Session{}, ConfigurePath: "components.session"},
	}
)

/**************** Component ****************/
func (r *Registry) UseComponent(componentNames ...string) error {
	var err error
	components := make([]*Component, 0)
	for _, componentName := range componentNames {
		canonicalComponentName := strings.ToUpper(componentName[0:1]) + componentName[1:]
		component := OptionalComponents.Get(canonicalComponentName)
		if component != nil {
			components = append(components, component)
			err = r.RegisterComponent(strings.ToLower(component.Name[0:1])+component.Name[1:], component.Component, true)
			if err != nil {
				return errors.Annotatef(err, errUseComponent, component.Name)
			}
		} else {
			return errors.Annotatef(err, errComponentNotExists, canonicalComponentName)
		}
	}
	sortedComponents := SortComponent(components)
	for _, name := range sortedComponents {
		component, err := r.GetComponentByName(name)
		if err != nil {
			return errors.Annotatef(err, errUseComponent, name)
		}
		err = r.InjectComponentTo([]interface{}{component})
		if err != nil {
			return errors.Annotatef(err, errUseComponent, name)
		}
	}
	return nil
}

// Register As Component
func (r *Registry) RegisterComponent(componentName string, component ComponentInterface, ignoreIfExistses ...bool) error {
	canonicalComponentName := strings.ToUpper(componentName[0:1]) + componentName[1:]
	ignoreIfExists := false
	if len(ignoreIfExistses) > 0 {
		ignoreIfExists = ignoreIfExistses[0]
	}
	if _, ok := r.ComponentMap[canonicalComponentName]; ok {
		if !ignoreIfExists {
			return errors.Errorf(errComponentExists, canonicalComponentName)
		}
		err := r.UnregisterComponent(canonicalComponentName)
		if err != nil {
			return errors.Annotatef(err, errRegisterComponent+": %s", canonicalComponentName)
		}
	}
	r.Components = append(r.Components, component)
	r.ComponentMap[canonicalComponentName] = component
	r.SortedComponentName = append(r.SortedComponentName, canonicalComponentName)
	return nil
}

// Unregister As Component
func (r *Registry) UnregisterComponent(componentNames ...string) error {
	if len(componentNames) > 0 {
		for _, componentName := range componentNames {
			canonicalComponentName := strings.ToUpper(componentName[0:1]) + componentName[1:]
			// r.ComponentMap
			delete(r.ComponentMap, canonicalComponentName)
			// r.SortedComponentName
			for index, sortedComponentName := range r.SortedComponentName {
				if canonicalComponentName == sortedComponentName {
					r.SortedComponentName = append(r.SortedComponentName[:index], r.SortedComponentName[index+1:]...)
				}
			}
			// r.Components
			for index, c := range r.Components {
				if component, ok := c.(*Component); ok {
					if canonicalComponentName == component.Name {
						r.Components = append(r.Components[:index], r.Components[index+1:]...)
					}
				}
			}
		}
	}
	return nil
}

func (r *Registry) GetComponentByName(componentName string) (interface{}, error) {
	canonicalComponentName := strings.ToUpper(componentName[0:1]) + componentName[1:]
	if _, ok := r.ComponentMap[canonicalComponentName]; !ok {
		return nil, errors.Errorf(errComponentNotExists, canonicalComponentName)
	}
	return r.ComponentMap[canonicalComponentName], nil
}

func (r *Registry) GetSortedComponents(reverses ...bool) []interface{} {
	components := make([]interface{}, len(r.Components))
	if len(r.SortedComponentName) > 0 {
		index := 0
		reverse := false
		if len(reverses) > 0 {
			reverse = reverses[0]
		}
		if reverse {
			for i := len(r.SortedComponentName) - 1; i >= 0; i-- {
				if component, ok := r.ComponentMap[r.SortedComponentName[i]]; ok {
					components[index] = component
					index++
				}
			}
		} else {
			for i := 0; i < len(r.SortedComponentName); i++ {
				if component, ok := r.ComponentMap[r.SortedComponentName[i]]; ok {
					components[index] = component
					index++
				}
			}
		}
	}
	return components
}

func (r *Registry) GetSortedComponentName() []string {
	return r.SortedComponentName
}

// Register As Value
func (r *Registry) RegisterValue(key string, value interface{}, forceOverwrites ...bool) error {
	Key := strings.ToUpper(key[0:1]) + key[1:]
	forceOverwrite := false
	if len(forceOverwrites) > 0 {
		forceOverwrite = forceOverwrites[0]
	}
	if _, ok := r.Values[Key]; ok && !forceOverwrite {
		return errors.Errorf(errValueExists, Key)
	}
	r.Values[Key] = value
	return nil
}

// Unregister As Value
func (r *Registry) UnregisterValue(keys ...string) error {
	if len(keys) > 0 {
		for _, key := range keys {
			Key := strings.ToUpper(key[0:1]) + key[1:]
			if _, ok := r.Values[Key]; !ok {
				return errors.Errorf(errValueNotExists, Key)
			}
			delete(r.Values, Key)
		}
	}
	return nil
}

func (r *Registry) GetValue(key string) (interface{}, error) {
	Key := strings.ToUpper(key[0:1]) + key[1:]
	if _, ok := r.Values[Key]; !ok {
		return nil, errors.Errorf(errValueNotExists, Key)
	}
	return r.Values[Key], nil
}

func (r *Registry) GetValues() map[string]interface{} {
	return r.Values
}

func (r *Registry) InjectComponent() error {
	return r.InjectComponentTo(r.GetSortedComponents())
}

func (r *Registry) InjectComponentByName(componentNames []string) error {
	componentMap := r.GetComponentMap()
	injectTargets := make([]interface{}, 0)
	for _, componentName := range componentNames {
		canonicalComponentName := strings.ToUpper(componentName[0:1]) + componentName[1:]
		if injectTarget, ok := componentMap[canonicalComponentName]; ok {
			injectTargets = append(injectTargets, injectTarget)
		}
	}
	return r.InjectComponentTo(injectTargets)
}

func (r *Registry) InjectComponentTo(injectTargets []interface{}) error {
	for _, injectTarget := range injectTargets {
		injectTargetValue := reflect.ValueOf(injectTarget)
		for injectTargetValue.Kind() == reflect.Ptr {
			injectTargetValue = injectTargetValue.Elem()
		}
		if injectTargetValue.Kind() != reflect.Struct {
			continue
		}
		s := structs.New(injectTarget)
		componentType := reflect.TypeOf((*ComponentInterface)(nil)).Elem()
		for _, f := range s.Fields() {
			if f.IsExported() && f.Tag(INJECT_TAG) == "true" {
				if reflect.TypeOf(f.Value()).Implements(componentType) {
					if _, ok := f.Value().(ComponentInterface); ok {
						fieldInjected := false
						if _, ok := r.ComponentMap[f.Name()]; ok {
							err := f.Set(r.ComponentMap[f.Name()])
							if err != nil {
								return errors.Annotatef(err, errInjectComponentTo, injectTargetValue.String(), f.Name())
							}
							fieldInjected = true
						}
						if !fieldInjected {
							return errors.Errorf(errInjectComponentTo+": component or key not exists", injectTargetValue.String(), f.Name())
						}
					}
				}
				if _, ok := r.Values[f.Name()]; ok {
					err := f.Set(r.Values[f.Name()])
					if err != nil {
						return errors.Annotatef(err, errInjectComponentTo, injectTargetValue.String(), f.Name())
					}
				}
			}
		}
	}
	return nil
}

/******** Component Dependency Manage ********/
// SortComponent - Sort user components.
func SortComponent(components []*Component) []string {
	// 初始化依赖关系
	for _, c := range components {
		if c.Dependencies == nil {
			c.Dependencies = make([]*Component, 0)
		}
		s := structs.New(c.Component)
		componentType := reflect.TypeOf((*ComponentInterface)(nil)).Elem()
		for _, f := range s.Fields() {
			if f.IsExported() && f.Tag(INJECT_TAG) == "true" {
				if reflect.TypeOf(f.Value()).Implements(componentType) {
					if dc, ok := f.Value().(ComponentInterface); ok {
						c.Dependencies = append(c.Dependencies, &Component{
							Name:      f.Name(),
							Component: dc,
						})
					}
				}
			}
		}
	}
	// root components
	roots := []*Component{}
	for _, c := range components {
		if len(c.Dependencies) == 0 {
			roots = append(roots, c)
		}
	}
	sortedComponents := make([]string, 0)
	return sortComponent(components, roots, sortedComponents)
}

// sortComponent
func sortComponent(components []*Component, currentComponents []*Component, sortedComponents []string) []string {
	if components != nil && currentComponents != nil && sortedComponents != nil {
		// 没有下级依赖
		if len(currentComponents) == 0 {
			return sortedComponents
		}
		for _, currentComponent := range currentComponents {
			// 当前层级组件
			index := utility.InArrayString(currentComponent.Name, sortedComponents, false)
			if index == nil {
				sortedComponents = append(sortedComponents, currentComponent.Name)
			} else {
				sortedComponents = append(sortedComponents[:*index], append(sortedComponents[*index+1:], sortedComponents[*index])...)
			}
			// 依赖当前级别组件的组件
			componentsNextLevel := make([]*Component, 0)
			for _, component := range components {
				for _, componentDependencie := range component.Dependencies {
					if strings.Compare(componentDependencie.Name, currentComponent.Name) == 0 {
						componentsNextLevel = append(componentsNextLevel, component)
					}
				}
			}
			sortedComponents = sortComponent(components, componentsNextLevel, sortedComponents)
		}
	}
	return sortedComponents
}

func (r *Registry) ConfigureComponentFileConfig(componentName string, configFile string, configProviders map[string]interface{}, configTag ...string) (err error) {
	canonicalComponentName := strings.ToUpper(componentName[0:1]) + componentName[1:]
	configComponent, err := r.GetComponentByName("Config")
	if err != nil {
		return errors.Annotatef(err, errConfigureComponentFileConfig, canonicalComponentName)
	}
	configer, ok := configComponent.(*config.Config)
	if !ok {
		return errors.Annotatef(errors.Errorf("invalid 'Config' component type"), errConfigureComponentFileConfig, canonicalComponentName)
	}
	// configer
	for componentName, component := range r.ComponentMap {
		canonicalExistsComponentName := strings.ToUpper(componentName[0:1]) + componentName[1:]
		if canonicalComponentName == canonicalExistsComponentName {
			if len(configTag) > 0 {
				// create a Config object
				err = configer.ConfigureFileConfig(component, configFile, configProviders, configTag...)
				if err != nil {
					return errors.Annotatef(err, errConfigureComponentFileConfig, canonicalComponentName)
				}
			}
		}
	}
	return nil
}
<commit_msg>component<commit_after>package ltick

import (
	"context"
	"reflect"
	"strings"

	"github.com/fatih/structs"
	"github.com/juju/errors"
	"github.com/ltick/tick-framework/config"
	"github.com/ltick/tick-framework/database"
	"github.com/ltick/tick-framework/filesystem"
	"github.com/ltick/tick-framework/kvstore"
	"github.com/ltick/tick-framework/logger"
	"github.com/ltick/tick-framework/queue"
	"github.com/ltick/tick-framework/session"
	"github.com/ltick/tick-framework/utility"
)

var (
	errComponentExists              = "ltick: component '%s' exists"
	errComponentNotExists           = "ltick: component '%s' not exists"
	errRegisterComponent            = "ltick: register component '%s' error"
	errUnregisterComponent          = "ltick: unregister component '%s' error"
	errInjectComponent              = "ltick: inject component '%s' field '%s' error"
	errInjectComponentTo            = "ltick: inject component '%s' field '%s' error"
	errUseComponent                 = "ltick: use component '%s' error"
	errValueExists                  = "ltick: value '%s' exists"
	errValueNotExists               = "ltick: value '%s' not exists"
	errConfigureComponentFileConfig = "ltick: configure component '%s' file config  error"
)

func (r *Registry) GetComponentMap() map[string]interface{} {
	return r.ComponentMap
}

type ComponentInterface interface {
	Initiate(ctx context.Context) (context.Context, error)
	OnStartup(ctx context.Context) (context.Context, error)
	OnShutdown(ctx context.Context) (context.Context, error)
}

type Components []*Component

func (cs Components) Get(name string) *Component {
	for _, c := range cs {
		canonicalName := strings.ToUpper(name[0:1]) + name[1:]
		if canonicalName == c.Name {
			return c
		}
	}
	return nil
}

type Component struct {
	Name          string
	Component     ComponentInterface
	ConfigurePath string
	Dependencies  []*Component
}

var (
	OptionalComponents = Components{
		&Component{Name: "Log", Component: &log.Logger{}, ConfigurePath: "components.log"},
		&Component{Name: "Database", Component: &database.Database{}, ConfigurePath: "components.database"},
		&Component{Name: "Kvstore", Component: &kvstore.Kvstore{}, ConfigurePath: "components.kvstore"},
		&Component{Name: "Queue", Component: &queue.Queue{}, ConfigurePath: "components.queue"},
		&Component{Name: "Filesystem", Component: &filesystem.Filesystem{}, ConfigurePath: "components.filesystem"},
		&Component{Name: "Session", Component: &session.Session{}, ConfigurePath: "components.session"},
	}
)

/**************** Component ****************/
func (r *Registry) UseComponent(componentNames ...string) error {
	var err error
	components := make([]*Component, 0)
	for _, componentName := range componentNames {
		canonicalComponentName := strings.ToUpper(componentName[0:1]) + componentName[1:]
		component := OptionalComponents.Get(canonicalComponentName)
		if component != nil {
			components = append(components, component)
			err = r.RegisterComponent(strings.ToLower(component.Name[0:1])+component.Name[1:], component.Component, true)
			if err != nil {
				return errors.Annotatef(err, errUseComponent, component.Name)
			}
		} else {
			return errors.Annotatef(err, errComponentNotExists, canonicalComponentName)
		}
	}
	sortedComponents := SortComponent(components)
	for _, name := range sortedComponents {
		component, err := r.GetComponentByName(name)
		if err != nil {
			return errors.Annotatef(err, errUseComponent, name)
		}
		err = r.InjectComponentTo([]interface{}{component})
		if err != nil {
			return errors.Annotatef(err, errUseComponent, name)
		}
	}
	return nil
}

// Register As Component
func (r *Registry) RegisterComponent(componentName string, component ComponentInterface, ignoreIfExistses ...bool) error {
	canonicalComponentName := strings.ToUpper(componentName[0:1]) + componentName[1:]
	ignoreIfExists := false
	if len(ignoreIfExistses) > 0 {
		ignoreIfExists = ignoreIfExistses[0]
	}
	if _, ok := r.ComponentMap[canonicalComponentName]; ok {
		if !ignoreIfExists {
			return errors.Errorf(errComponentExists, canonicalComponentName)
		}
		err := r.UnregisterComponent(canonicalComponentName)
		if err != nil {
			return errors.Annotatef(err, errRegisterComponent+": %s", canonicalComponentName)
		}
	}
	r.Components = append(r.Components, component)
	r.ComponentMap[canonicalComponentName] = component
	r.SortedComponentName = append(r.SortedComponentName, canonicalComponentName)
	return nil
}

// Unregister As Component
func (r *Registry) UnregisterComponent(componentNames ...string) error {
	if len(componentNames) > 0 {
		for _, componentName := range componentNames {
			canonicalComponentName := strings.ToUpper(componentName[0:1]) + componentName[1:]
			// r.ComponentMap
			delete(r.ComponentMap, canonicalComponentName)
			// r.SortedComponentName
			for index, sortedComponentName := range r.SortedComponentName {
				if canonicalComponentName == sortedComponentName {
					r.SortedComponentName = append(r.SortedComponentName[:index], r.SortedComponentName[index+1:]...)
				}
			}
			// r.Components
			for index, c := range r.Components {
				if component, ok := c.(*Component); ok {
					if canonicalComponentName == component.Name {
						r.Components = append(r.Components[:index], r.Components[index+1:]...)
					}
				}
			}
		}
	}
	return nil
}

func (r *Registry) GetComponentByName(componentName string) (interface{}, error) {
	canonicalComponentName := strings.ToUpper(componentName[0:1]) + componentName[1:]
	if _, ok := r.ComponentMap[canonicalComponentName]; !ok {
		return nil, errors.Errorf(errComponentNotExists, canonicalComponentName)
	}
	return r.ComponentMap[canonicalComponentName], nil
}

func (r *Registry) GetSortedComponents(reverses ...bool) []interface{} {
	components := make([]interface{}, len(r.Components))
	if len(r.SortedComponentName) > 0 {
		index := 0
		reverse := false
		if len(reverses) > 0 {
			reverse = reverses[0]
		}
		if reverse {
			for i := len(r.SortedComponentName) - 1; i >= 0; i-- {
				if component, ok := r.ComponentMap[r.SortedComponentName[i]]; ok {
					components[index] = component
					index++
				}
			}
		} else {
			for i := 0; i < len(r.SortedComponentName); i++ {
				if component, ok := r.ComponentMap[r.SortedComponentName[i]]; ok {
					components[index] = component
					index++
				}
			}
		}
	}
	return components
}

func (r *Registry) GetSortedComponentName() []string {
	return r.SortedComponentName
}

// Register As Value
func (r *Registry) RegisterValue(key string, value interface{}, forceOverwrites ...bool) error {
	Key := strings.ToUpper(key[0:1]) + key[1:]
	forceOverwrite := false
	if len(forceOverwrites) > 0 {
		forceOverwrite = forceOverwrites[0]
	}
	if _, ok := r.Values[Key]; ok && !forceOverwrite {
		return errors.Errorf(errValueExists, Key)
	}
	r.Values[Key] = value
	return nil
}

// Unregister As Value
func (r *Registry) UnregisterValue(keys ...string) error {
	if len(keys) > 0 {
		for _, key := range keys {
			Key := strings.ToUpper(key[0:1]) + key[1:]
			if _, ok := r.Values[Key]; !ok {
				return errors.Errorf(errValueNotExists, Key)
			}
			delete(r.Values, Key)
		}
	}
	return nil
}

func (r *Registry) GetValue(key string) (interface{}, error) {
	Key := strings.ToUpper(key[0:1]) + key[1:]
	if _, ok := r.Values[Key]; !ok {
		return nil, errors.Errorf(errValueNotExists, Key)
	}
	return r.Values[Key], nil
}

func (r *Registry) GetValues() map[string]interface{} {
	return r.Values
}

func (r *Registry) InjectComponent() error {
	return r.InjectComponentTo(r.GetSortedComponents())
}

func (r *Registry) InjectComponentByName(componentNames []string) error {
	componentMap := r.GetComponentMap()
	injectTargets := make([]interface{}, 0)
	for _, componentName := range componentNames {
		canonicalComponentName := strings.ToUpper(componentName[0:1]) + componentName[1:]
		if injectTarget, ok := componentMap[canonicalComponentName]; ok {
			injectTargets = append(injectTargets, injectTarget)
		}
	}
	return r.InjectComponentTo(injectTargets)
}

func (r *Registry) InjectComponentTo(injectTargets []interface{}) error {
	for _, injectTarget := range injectTargets {
		injectTargetValue := reflect.ValueOf(injectTarget)
		for injectTargetValue.Kind() == reflect.Ptr {
			injectTargetValue = injectTargetValue.Elem()
		}
		if injectTargetValue.Kind() != reflect.Struct {
			continue
		}
		s := structs.New(injectTarget)
		componentType := reflect.TypeOf((*ComponentInterface)(nil)).Elem()
		for _, f := range s.Fields() {
			if f.IsExported() && f.Tag(INJECT_TAG) == "true" {
				if reflect.TypeOf(f.Value()).Implements(componentType) {
					if _, ok := f.Value().(ComponentInterface); ok {
						fieldInjected := false
						if _, ok := r.ComponentMap[f.Name()]; ok {
							err := f.Set(r.ComponentMap[f.Name()])
							if err != nil {
								return errors.Annotatef(err, errInjectComponentTo, injectTargetValue.String(), f.Name())
							}
							fieldInjected = true
						}
						if !fieldInjected {
							return errors.Errorf(errInjectComponentTo+": component or key not exists", injectTargetValue.String(), f.Name())
						}
					}
				}
				if _, ok := r.Values[f.Name()]; ok {
					err := f.Set(r.Values[f.Name()])
					if err != nil {
						return errors.Annotatef(err, errInjectComponentTo, injectTargetValue.String(), f.Name())
					}
				}
			}
		}
	}
	return nil
}

/******** Component Dependency Manage ********/
// SortComponent - Sort user components.
func SortComponent(components []*Component) []string {
	// 初始化依赖关系
	for _, c := range components {
		if c.Dependencies == nil {
			c.Dependencies = make([]*Component, 0)
		}
		s := structs.New(c.Component)
		componentType := reflect.TypeOf((*ComponentInterface)(nil)).Elem()
		for _, f := range s.Fields() {
			if f.IsExported() && f.Tag(INJECT_TAG) == "true" {
				if reflect.TypeOf(f.Value()).Implements(componentType) {
					if dc, ok := f.Value().(ComponentInterface); ok {
						c.Dependencies = append(c.Dependencies, &Component{
							Name:      f.Name(),
							Component: dc,
						})
					}
				}
			}
		}
	}
	// root components
	roots := []*Component{}
	for {
		rootDependenciesCount := 0
		for _, c := range components {
			if len(c.Dependencies) == rootDependenciesCount {
				roots = append(roots, c)
			}
		}
		if len(roots) > 0 {
			break
		} else {
			rootDependenciesCount++
		}
	}

	sortedComponents := make([]string, 0)
	return sortComponent(components, roots, sortedComponents)
}

// sortComponent
func sortComponent(components []*Component, currentComponents []*Component, sortedComponents []string) []string {
	if components != nil && currentComponents != nil && sortedComponents != nil {
		// 没有下级依赖
		if len(currentComponents) == 0 {
			return sortedComponents
		}
		for _, currentComponent := range currentComponents {
			// 当前层级组件
			index := utility.InArrayString(currentComponent.Name, sortedComponents, false)
			if index == nil {
				sortedComponents = append(sortedComponents, currentComponent.Name)
			} else {
				sortedComponents = append(sortedComponents[:*index], append(sortedComponents[*index+1:], sortedComponents[*index])...)
			}
			// 依赖当前级别组件的组件
			componentsNextLevel := make([]*Component, 0)
			for _, component := range components {
				for _, componentDependencie := range component.Dependencies {
					if strings.Compare(componentDependencie.Name, currentComponent.Name) == 0 {
						componentsNextLevel = append(componentsNextLevel, component)
					}
				}
			}
			sortedComponents = sortComponent(components, componentsNextLevel, sortedComponents)
		}
	}
	return sortedComponents
}

func (r *Registry) ConfigureComponentFileConfig(componentName string, configFile string, configProviders map[string]interface{}, configTag ...string) (err error) {
	canonicalComponentName := strings.ToUpper(componentName[0:1]) + componentName[1:]
	configComponent, err := r.GetComponentByName("Config")
	if err != nil {
		return errors.Annotatef(err, errConfigureComponentFileConfig, canonicalComponentName)
	}
	configer, ok := configComponent.(*config.Config)
	if !ok {
		return errors.Annotatef(errors.Errorf("invalid 'Config' component type"), errConfigureComponentFileConfig, canonicalComponentName)
	}
	// configer
	for componentName, component := range r.ComponentMap {
		canonicalExistsComponentName := strings.ToUpper(componentName[0:1]) + componentName[1:]
		if canonicalComponentName == canonicalExistsComponentName {
			if len(configTag) > 0 {
				// create a Config object
				err = configer.ConfigureFileConfig(component, configFile, configProviders, configTag...)
				if err != nil {
					return errors.Annotatef(err, errConfigureComponentFileConfig, canonicalComponentName)
				}
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the
//  License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing,
//  software distributed under the License is distributed on an "AS
//  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//  express or implied. See the License for the specific language
//  governing permissions and limitations under the License.

package cbgt

import (
	"fmt"
)

// The cbgt.VERSION tracks persistence versioning (schema/format of
// persisted data and configuration).  The main.VERSION that's part of
// an executable command, in contrast, is an overall "product"
// version.  For example, we might introduce new UI-only features or
// fix a UI typo, in which case we'd bump the main.VERSION number;
// but, if the persisted data/config format was unchanged, then the
// cbgt.VERSION number should remain unchanged.
//
// NOTE: You *must* update cbgt.VERSION if you change what's stored in
// the Cfg (such as the JSON/struct definitions or the planning
// algorithms).
const VERSION = "4.0.0"
const VERSION_KEY = "version"

// Returns true if a given version is modern enough to modify the Cfg.
// Older versions (which are running with older JSON/struct defintions
// or planning algorithms) will see false from their CheckVersion()'s.
func CheckVersion(cfg Cfg, myVersion string) (bool, error) {
	for cfg != nil {
		clusterVersion, cas, err := cfg.Get(VERSION_KEY, 0)
		if err != nil {
			return false, err
		}
		if clusterVersion == nil {
			// First time initialization, so save myVersion to cfg and
			// retry in case there was a race.
			_, err = cfg.Set(VERSION_KEY, []byte(myVersion), cas)
			if err != nil {
				return false, fmt.Errorf("version:"+
					" could not save VERSION to cfg, err: %v", err)
			}
			continue
		}
		if VersionGTE(myVersion, string(clusterVersion)) == false {
			return false, nil
		}
		if myVersion != string(clusterVersion) {
			// Found myVersion is higher than clusterVersion so save
			// myVersion to cfg and retry in case there was a race.
			_, err = cfg.Set(VERSION_KEY, []byte(myVersion), cas)
			if err != nil {
				return false, fmt.Errorf("version:"+
					" could not update VERSION in cfg, err: %v", err)
			}
			continue
		}
		return true, nil
	}

	return false, nil
}
<commit_msg>update versioning comment<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the
//  License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing,
//  software distributed under the License is distributed on an "AS
//  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//  express or implied. See the License for the specific language
//  governing permissions and limitations under the License.

package cbgt

import (
	"fmt"
)

// The cbgt.VERSION tracks persistence versioning (schema/format of
// persisted data and configuration).  The main.VERSION from "git
// describe" that's part of an executable command, in contrast, is an
// overall "product" version.  For example, we might introduce new
// UI-only features or fix a UI typo, in which case we'd bump the
// main.VERSION number; but, if the persisted data/config format was
// unchanged, then the cbgt.VERSION number should remain unchanged.
//
// NOTE: You *must* update cbgt.VERSION if you change what's stored in
// the Cfg (such as the JSON/struct definitions or the planning
// algorithms).
const VERSION = "4.0.0"
const VERSION_KEY = "version"

// Returns true if a given version is modern enough to modify the Cfg.
// Older versions (which are running with older JSON/struct defintions
// or planning algorithms) will see false from their CheckVersion()'s.
func CheckVersion(cfg Cfg, myVersion string) (bool, error) {
	for cfg != nil {
		clusterVersion, cas, err := cfg.Get(VERSION_KEY, 0)
		if err != nil {
			return false, err
		}
		if clusterVersion == nil {
			// First time initialization, so save myVersion to cfg and
			// retry in case there was a race.
			_, err = cfg.Set(VERSION_KEY, []byte(myVersion), cas)
			if err != nil {
				return false, fmt.Errorf("version:"+
					" could not save VERSION to cfg, err: %v", err)
			}
			continue
		}
		if VersionGTE(myVersion, string(clusterVersion)) == false {
			return false, nil
		}
		if myVersion != string(clusterVersion) {
			// Found myVersion is higher than clusterVersion so save
			// myVersion to cfg and retry in case there was a race.
			_, err = cfg.Set(VERSION_KEY, []byte(myVersion), cas)
			if err != nil {
				return false, fmt.Errorf("version:"+
					" could not update VERSION in cfg, err: %v", err)
			}
			continue
		}
		return true, nil
	}

	return false, nil
}
<|endoftext|>


<commit_before>package main

const VERSION = "0.6.0-alpha1"
<commit_msg>:tada: Bump up the version<commit_after>package main

const VERSION = "0.6.0"
<|endoftext|>


<commit_before>package main

const Name string = "locksmith"
const Version string = "0.10"
<commit_msg>Bump to 0.11<commit_after>package main

const Name string = "locksmith"
const Version string = "0.11"
<|endoftext|>


<commit_before>package main

// Name of this tool
const Name string = "gol"

// Version of this tool
const Version string = "0.1.0"
<commit_msg>release v0.6.0<commit_after>package main

// Name of this tool
const Name string = "gol"

// Version of this tool
const Version string = "0.6.0"
<|endoftext|>


<commit_before>// Package gosnowflake is a Go Snowflake Driver for Go's database/sql
//
// Copyright (c) 2017 Snowflake Computing Inc. All right reserved.
//
package gosnowflake

// SnowflakeGoDriverVersion is the version of Go Snowflake Driver
const SnowflakeGoDriverVersion = "0.4.0"
<commit_msg>Bumping up version to 0.5.0<commit_after>// Package gosnowflake is a Go Snowflake Driver for Go's database/sql
//
// Copyright (c) 2017 Snowflake Computing Inc. All right reserved.
//
package gosnowflake

// SnowflakeGoDriverVersion is the version of Go Snowflake Driver
const SnowflakeGoDriverVersion = "0.5.0"
<|endoftext|>


<commit_before>package libsacloud

// Version バージョン
const Version = "2.0.0-beta1"
<commit_msg>Bump to v2.0.0-beta2<commit_after>package libsacloud

// Version バージョン
const Version = "2.0.0-beta2"
<|endoftext|>


<commit_before>package gock

// Version defines the current package semantic version.
const Version = "0.1.0"
<commit_msg>feat(version): bump<commit_after>package gock

// Version defines the current package semantic version.
const Version = "0.1.1"
<|endoftext|>


<commit_before>package sarama

import (
	"time"
)

// OffsetMethod is passed in ConsumerConfig to tell the consumer how to determine the starting offset.
type OffsetMethod int

const (
	// OffsetMethodManual causes the consumer to interpret the OffsetValue in the ConsumerConfig as the
	// offset at which to start, allowing the user to manually specify their desired starting offset.
	OffsetMethodManual OffsetMethod = iota
	// OffsetMethodNewest causes the consumer to start at the most recent available offset, as
	// determined by querying the broker.
	OffsetMethodNewest
	// OffsetMethodOldest causes the consumer to start at the oldest available offset, as
	// determined by querying the broker.
	OffsetMethodOldest
)

// ConsumerConfig is used to pass multiple configuration options to NewConsumer.
type ConsumerConfig struct {
	// The default (maximum) amount of data to fetch from the broker in each request. The default is 32768 bytes.
	DefaultFetchSize int32
	// The minimum amount of data to fetch in a request - the broker will wait until at least this many bytes are available.
	// The default is 1, as 0 causes the consumer to spin when no messages are available.
	MinFetchSize int32
	// The maximum permittable message size - messages larger than this will return MessageTooLarge. The default of 0 is
	// treated as no limit.
	MaxMessageSize int32
	// The maximum amount of time the broker will wait for MinFetchSize bytes to become available before it
	// returns fewer than that anyways. The default is 250ms, since 0 causes the consumer to spin when no events are available.
	// 100-500ms is a reasonable range for most cases. Kafka only supports precision up to milliseconds; nanoseconds will be truncated.
	MaxWaitTime time.Duration

	// The method used to determine at which offset to begin consuming messages.
	OffsetMethod OffsetMethod
	// Interpreted differently according to the value of OffsetMethod.
	OffsetValue int64

	// The number of events to buffer in the Events channel. Having this non-zero permits the
	// consumer to continue fetching messages in the background while client code consumes events,
	// greatly improving throughput. The default is 16.
	EventBufferSize int
}

// ConsumerEvent is what is provided to the user when an event occurs. It is either an error (in which case Err is non-nil) or
// a message (in which case Err is nil and Offset, Key, and Value are set). Topic and Partition are always set.
type ConsumerEvent struct {
	Key, Value []byte
	Topic      string
	Partition  int32
	Offset     int64
	Err        error
}

// Consumer processes Kafka messages from a given topic and partition.
// You MUST call Close() on a consumer to avoid leaks, it will not be garbage-collected automatically when
// it passes out of scope (this is in addition to calling Close on the underlying client, which is still necessary).
type Consumer struct {
	client *Client

	topic     string
	partition int32
	group     string
	config    ConsumerConfig

	offset        int64
	broker        *Broker
	stopper, done chan bool
	events        chan *ConsumerEvent
}

// NewConsumer creates a new consumer attached to the given client. It will read messages from the given topic and partition, as
// part of the named consumer group.
func NewConsumer(client *Client, topic string, partition int32, group string, config *ConsumerConfig) (*Consumer, error) {
	// Check that we are not dealing with a closed Client before processing
	// any other arguments
	if client.Closed() {
		return nil, ClosedClient
	}

	if config == nil {
		config = NewConsumerConfig()
	}

	if err := config.Validate(); err != nil {
		return nil, err
	}

	if topic == "" {
		return nil, ConfigurationError("Empty topic")
	}

	broker, err := client.Leader(topic, partition)
	if err != nil {
		return nil, err
	}

	c := &Consumer{
		client:    client,
		topic:     topic,
		partition: partition,
		group:     group,
		config:    *config,
		broker:    broker,
		stopper:   make(chan bool),
		done:      make(chan bool),
		events:    make(chan *ConsumerEvent, config.EventBufferSize),
	}

	switch config.OffsetMethod {
	case OffsetMethodManual:
		if config.OffsetValue < 0 {
			return nil, ConfigurationError("OffsetValue cannot be < 0 when OffsetMethod is MANUAL")
		}
		c.offset = config.OffsetValue
	case OffsetMethodNewest:
		c.offset, err = c.getOffset(LatestOffsets, true)
		if err != nil {
			return nil, err
		}
	case OffsetMethodOldest:
		c.offset, err = c.getOffset(EarliestOffset, true)
		if err != nil {
			return nil, err
		}
	default:
		return nil, ConfigurationError("Invalid OffsetMethod")
	}

	go withRecover(c.fetchMessages)

	return c, nil
}

// Events returns the read channel for any events (messages or errors) that might be returned by the broker.
func (c *Consumer) Events() <-chan *ConsumerEvent {
	return c.events
}

// Close stops the consumer from fetching messages. It is required to call this function before
// a consumer object passes out of scope, as it will otherwise leak memory. You must call this before
// calling Close on the underlying client.
func (c *Consumer) Close() error {
	close(c.stopper)
	<-c.done
	return nil
}

// helper function for safely sending an error on the errors channel
// if it returns true, the error was sent (or was nil)
// if it returns false, the stopper channel signaled that your goroutine should return!
func (c *Consumer) sendError(err error) bool {
	if err == nil {
		return true
	}

	select {
	case <-c.stopper:
		close(c.events)
		close(c.done)
		return false
	case c.events <- &ConsumerEvent{Err: err, Topic: c.topic, Partition: c.partition}:
		return true
	}
}

func (c *Consumer) fetchMessages() {

	fetchSize := c.config.DefaultFetchSize

	for {
		request := new(FetchRequest)
		request.MinBytes = c.config.MinFetchSize
		request.MaxWaitTime = int32(c.config.MaxWaitTime / time.Millisecond)
		request.AddBlock(c.topic, c.partition, c.offset, fetchSize)

		response, err := c.broker.Fetch(c.client.id, request)
		switch {
		case err == nil:
			break
		case err == EncodingError:
			if c.sendError(err) {
				continue
			} else {
				return
			}
		default:
			Logger.Printf("Unexpected error processing FetchRequest; disconnecting broker %s: %s\n", c.broker.addr, err)
			c.client.disconnectBroker(c.broker)
			for c.broker, err = c.client.Leader(c.topic, c.partition); err != nil; c.broker, err = c.client.Leader(c.topic, c.partition) {
				if !c.sendError(err) {
					return
				}
			}
			continue
		}

		block := response.GetBlock(c.topic, c.partition)
		if block == nil {
			if c.sendError(IncompleteResponse) {
				continue
			} else {
				return
			}
		}

		switch block.Err {
		case NoError:
			break
		case UnknownTopicOrPartition, NotLeaderForPartition, LeaderNotAvailable:
			err = c.client.RefreshTopicMetadata(c.topic)
			if c.sendError(err) {
				for c.broker, err = c.client.Leader(c.topic, c.partition); err != nil; c.broker, err = c.client.Leader(c.topic, c.partition) {
					if !c.sendError(err) {
						return
					}
				}
				continue
			} else {
				return
			}
		default:
			if c.sendError(block.Err) {
				continue
			} else {
				return
			}
		}

		if len(block.MsgSet.Messages) == 0 {
			// We got no messages. If we got a trailing one then we need to ask for more data.
			// Otherwise we just poll again and wait for one to be produced...
			if block.MsgSet.PartialTrailingMessage {
				if c.config.MaxMessageSize == 0 {
					fetchSize *= 2
				} else {
					if fetchSize == c.config.MaxMessageSize {
						if c.sendError(MessageTooLarge) {
							continue
						} else {
							return
						}
					} else {
						fetchSize *= 2
						if fetchSize > c.config.MaxMessageSize {
							fetchSize = c.config.MaxMessageSize
						}
					}
				}
			}
			select {
			case <-c.stopper:
				close(c.events)
				close(c.done)
				return
			default:
				continue
			}
		} else {
			fetchSize = c.config.DefaultFetchSize
		}

		for _, msgBlock := range block.MsgSet.Messages {
			for _, msg := range msgBlock.Messages() {

				event := &ConsumerEvent{Topic: c.topic, Partition: c.partition}
				if msg.Offset != c.offset {
					event.Err = IncompleteResponse
				} else {
					event.Key = msg.Msg.Key
					event.Value = msg.Msg.Value
					event.Offset = msg.Offset
					c.offset++
				}

				select {
				case <-c.stopper:
					close(c.events)
					close(c.done)
					return
				case c.events <- event:
				}
			}
		}
	}
}

func (c *Consumer) getOffset(where OffsetTime, retry bool) (int64, error) {
	offset, err := c.client.GetOffset(c.topic, c.partition, where)

	switch err {
	case nil:
		break
	case EncodingError:
		return -1, err
	default:
		if !retry {
			return -1, err
		}

		switch err.(type) {
		case KError:
			switch err {
			case UnknownTopicOrPartition, NotLeaderForPartition, LeaderNotAvailable:
				err = c.client.RefreshTopicMetadata(c.topic)
				if err != nil {
					return -1, err
				}
			default:
				Logger.Printf("Unexpected error processing OffsetRequest; disconnecting broker %s: %s\n", c.broker.addr, err)
				c.client.disconnectBroker(c.broker)

				broker, brokerErr := c.client.Leader(c.topic, c.partition)
				if brokerErr != nil {
					return -1, brokerErr
				}
				c.broker = broker
			}
			return c.getOffset(where, false)
		}
		return -1, err
	}
	return offset, nil
}

// NewConsumerConfig creates a ConsumerConfig instance with sane defaults.
func NewConsumerConfig() *ConsumerConfig {
	return &ConsumerConfig{
		DefaultFetchSize: 32768,
		MinFetchSize:     1,
		MaxWaitTime:      250 * time.Millisecond,
		EventBufferSize:  16,
	}
}

// Validate checks a ConsumerConfig instance. It will return a
// ConfigurationError if the specified value doesn't make sense.
func (config *ConsumerConfig) Validate() error {
	if config.DefaultFetchSize <= 0 {
		return ConfigurationError("Invalid DefaultFetchSize")
	}

	if config.MinFetchSize <= 0 {
		return ConfigurationError("Invalid MinFetchSize")
	}

	if config.MaxMessageSize < 0 {
		return ConfigurationError("Invalid MaxMessageSize")
	}

	if config.MaxWaitTime < 1*time.Millisecond {
		return ConfigurationError("Invalid MaxWaitTime, it needs to be at least 1ms")
	} else if config.MaxWaitTime < 100*time.Millisecond {
		Logger.Println("ConsumerConfig.MaxWaitTime is very low, which can cause high CPU and network usage. See documentation for details.")
	} else if config.MaxWaitTime%time.Millisecond != 0 {
		Logger.Println("ConsumerConfig.MaxWaitTime only supports millisecond precision; nanoseconds will be truncated.")
	}

	if config.EventBufferSize < 0 {
		return ConfigurationError("Invalid EventBufferSize")
	}

	return nil
}
<commit_msg>consumer: silently skip messages already consumed<commit_after>package sarama

import (
	"time"
)

// OffsetMethod is passed in ConsumerConfig to tell the consumer how to determine the starting offset.
type OffsetMethod int

const (
	// OffsetMethodManual causes the consumer to interpret the OffsetValue in the ConsumerConfig as the
	// offset at which to start, allowing the user to manually specify their desired starting offset.
	OffsetMethodManual OffsetMethod = iota
	// OffsetMethodNewest causes the consumer to start at the most recent available offset, as
	// determined by querying the broker.
	OffsetMethodNewest
	// OffsetMethodOldest causes the consumer to start at the oldest available offset, as
	// determined by querying the broker.
	OffsetMethodOldest
)

// ConsumerConfig is used to pass multiple configuration options to NewConsumer.
type ConsumerConfig struct {
	// The default (maximum) amount of data to fetch from the broker in each request. The default is 32768 bytes.
	DefaultFetchSize int32
	// The minimum amount of data to fetch in a request - the broker will wait until at least this many bytes are available.
	// The default is 1, as 0 causes the consumer to spin when no messages are available.
	MinFetchSize int32
	// The maximum permittable message size - messages larger than this will return MessageTooLarge. The default of 0 is
	// treated as no limit.
	MaxMessageSize int32
	// The maximum amount of time the broker will wait for MinFetchSize bytes to become available before it
	// returns fewer than that anyways. The default is 250ms, since 0 causes the consumer to spin when no events are available.
	// 100-500ms is a reasonable range for most cases. Kafka only supports precision up to milliseconds; nanoseconds will be truncated.
	MaxWaitTime time.Duration

	// The method used to determine at which offset to begin consuming messages.
	OffsetMethod OffsetMethod
	// Interpreted differently according to the value of OffsetMethod.
	OffsetValue int64

	// The number of events to buffer in the Events channel. Having this non-zero permits the
	// consumer to continue fetching messages in the background while client code consumes events,
	// greatly improving throughput. The default is 16.
	EventBufferSize int
}

// ConsumerEvent is what is provided to the user when an event occurs. It is either an error (in which case Err is non-nil) or
// a message (in which case Err is nil and Offset, Key, and Value are set). Topic and Partition are always set.
type ConsumerEvent struct {
	Key, Value []byte
	Topic      string
	Partition  int32
	Offset     int64
	Err        error
}

// Consumer processes Kafka messages from a given topic and partition.
// You MUST call Close() on a consumer to avoid leaks, it will not be garbage-collected automatically when
// it passes out of scope (this is in addition to calling Close on the underlying client, which is still necessary).
type Consumer struct {
	client *Client

	topic     string
	partition int32
	group     string
	config    ConsumerConfig

	offset        int64
	broker        *Broker
	stopper, done chan bool
	events        chan *ConsumerEvent
}

// NewConsumer creates a new consumer attached to the given client. It will read messages from the given topic and partition, as
// part of the named consumer group.
func NewConsumer(client *Client, topic string, partition int32, group string, config *ConsumerConfig) (*Consumer, error) {
	// Check that we are not dealing with a closed Client before processing
	// any other arguments
	if client.Closed() {
		return nil, ClosedClient
	}

	if config == nil {
		config = NewConsumerConfig()
	}

	if err := config.Validate(); err != nil {
		return nil, err
	}

	if topic == "" {
		return nil, ConfigurationError("Empty topic")
	}

	broker, err := client.Leader(topic, partition)
	if err != nil {
		return nil, err
	}

	c := &Consumer{
		client:    client,
		topic:     topic,
		partition: partition,
		group:     group,
		config:    *config,
		broker:    broker,
		stopper:   make(chan bool),
		done:      make(chan bool),
		events:    make(chan *ConsumerEvent, config.EventBufferSize),
	}

	switch config.OffsetMethod {
	case OffsetMethodManual:
		if config.OffsetValue < 0 {
			return nil, ConfigurationError("OffsetValue cannot be < 0 when OffsetMethod is MANUAL")
		}
		c.offset = config.OffsetValue
	case OffsetMethodNewest:
		c.offset, err = c.getOffset(LatestOffsets, true)
		if err != nil {
			return nil, err
		}
	case OffsetMethodOldest:
		c.offset, err = c.getOffset(EarliestOffset, true)
		if err != nil {
			return nil, err
		}
	default:
		return nil, ConfigurationError("Invalid OffsetMethod")
	}

	go withRecover(c.fetchMessages)

	return c, nil
}

// Events returns the read channel for any events (messages or errors) that might be returned by the broker.
func (c *Consumer) Events() <-chan *ConsumerEvent {
	return c.events
}

// Close stops the consumer from fetching messages. It is required to call this function before
// a consumer object passes out of scope, as it will otherwise leak memory. You must call this before
// calling Close on the underlying client.
func (c *Consumer) Close() error {
	close(c.stopper)
	<-c.done
	return nil
}

// helper function for safely sending an error on the errors channel
// if it returns true, the error was sent (or was nil)
// if it returns false, the stopper channel signaled that your goroutine should return!
func (c *Consumer) sendError(err error) bool {
	if err == nil {
		return true
	}

	select {
	case <-c.stopper:
		close(c.events)
		close(c.done)
		return false
	case c.events <- &ConsumerEvent{Err: err, Topic: c.topic, Partition: c.partition}:
		return true
	}
}

func (c *Consumer) fetchMessages() {

	fetchSize := c.config.DefaultFetchSize

	for {
		request := new(FetchRequest)
		request.MinBytes = c.config.MinFetchSize
		request.MaxWaitTime = int32(c.config.MaxWaitTime / time.Millisecond)
		request.AddBlock(c.topic, c.partition, c.offset, fetchSize)

		response, err := c.broker.Fetch(c.client.id, request)
		switch {
		case err == nil:
			break
		case err == EncodingError:
			if c.sendError(err) {
				continue
			} else {
				return
			}
		default:
			Logger.Printf("Unexpected error processing FetchRequest; disconnecting broker %s: %s\n", c.broker.addr, err)
			c.client.disconnectBroker(c.broker)
			for c.broker, err = c.client.Leader(c.topic, c.partition); err != nil; c.broker, err = c.client.Leader(c.topic, c.partition) {
				if !c.sendError(err) {
					return
				}
			}
			continue
		}

		block := response.GetBlock(c.topic, c.partition)
		if block == nil {
			if c.sendError(IncompleteResponse) {
				continue
			} else {
				return
			}
		}

		switch block.Err {
		case NoError:
			break
		case UnknownTopicOrPartition, NotLeaderForPartition, LeaderNotAvailable:
			err = c.client.RefreshTopicMetadata(c.topic)
			if c.sendError(err) {
				for c.broker, err = c.client.Leader(c.topic, c.partition); err != nil; c.broker, err = c.client.Leader(c.topic, c.partition) {
					if !c.sendError(err) {
						return
					}
				}
				continue
			} else {
				return
			}
		default:
			if c.sendError(block.Err) {
				continue
			} else {
				return
			}
		}

		if len(block.MsgSet.Messages) == 0 {
			// We got no messages. If we got a trailing one then we need to ask for more data.
			// Otherwise we just poll again and wait for one to be produced...
			if block.MsgSet.PartialTrailingMessage {
				if c.config.MaxMessageSize == 0 {
					fetchSize *= 2
				} else {
					if fetchSize == c.config.MaxMessageSize {
						if c.sendError(MessageTooLarge) {
							continue
						} else {
							return
						}
					} else {
						fetchSize *= 2
						if fetchSize > c.config.MaxMessageSize {
							fetchSize = c.config.MaxMessageSize
						}
					}
				}
			}
			select {
			case <-c.stopper:
				close(c.events)
				close(c.done)
				return
			default:
				continue
			}
		} else {
			fetchSize = c.config.DefaultFetchSize
		}

		for _, msgBlock := range block.MsgSet.Messages {
			for _, msg := range msgBlock.Messages() {

				event := &ConsumerEvent{Topic: c.topic, Partition: c.partition}
				if msg.Offset < c.offset {
					continue
				} else if msg.Offset > c.offset {
					event.Err = IncompleteResponse
				} else {
					event.Key = msg.Msg.Key
					event.Value = msg.Msg.Value
					event.Offset = msg.Offset
					c.offset++
				}

				select {
				case <-c.stopper:
					close(c.events)
					close(c.done)
					return
				case c.events <- event:
				}
			}
		}
	}
}

func (c *Consumer) getOffset(where OffsetTime, retry bool) (int64, error) {
	offset, err := c.client.GetOffset(c.topic, c.partition, where)

	switch err {
	case nil:
		break
	case EncodingError:
		return -1, err
	default:
		if !retry {
			return -1, err
		}

		switch err.(type) {
		case KError:
			switch err {
			case UnknownTopicOrPartition, NotLeaderForPartition, LeaderNotAvailable:
				err = c.client.RefreshTopicMetadata(c.topic)
				if err != nil {
					return -1, err
				}
			default:
				Logger.Printf("Unexpected error processing OffsetRequest; disconnecting broker %s: %s\n", c.broker.addr, err)
				c.client.disconnectBroker(c.broker)

				broker, brokerErr := c.client.Leader(c.topic, c.partition)
				if brokerErr != nil {
					return -1, brokerErr
				}
				c.broker = broker
			}
			return c.getOffset(where, false)
		}
		return -1, err
	}
	return offset, nil
}

// NewConsumerConfig creates a ConsumerConfig instance with sane defaults.
func NewConsumerConfig() *ConsumerConfig {
	return &ConsumerConfig{
		DefaultFetchSize: 32768,
		MinFetchSize:     1,
		MaxWaitTime:      250 * time.Millisecond,
		EventBufferSize:  16,
	}
}

// Validate checks a ConsumerConfig instance. It will return a
// ConfigurationError if the specified value doesn't make sense.
func (config *ConsumerConfig) Validate() error {
	if config.DefaultFetchSize <= 0 {
		return ConfigurationError("Invalid DefaultFetchSize")
	}

	if config.MinFetchSize <= 0 {
		return ConfigurationError("Invalid MinFetchSize")
	}

	if config.MaxMessageSize < 0 {
		return ConfigurationError("Invalid MaxMessageSize")
	}

	if config.MaxWaitTime < 1*time.Millisecond {
		return ConfigurationError("Invalid MaxWaitTime, it needs to be at least 1ms")
	} else if config.MaxWaitTime < 100*time.Millisecond {
		Logger.Println("ConsumerConfig.MaxWaitTime is very low, which can cause high CPU and network usage. See documentation for details.")
	} else if config.MaxWaitTime%time.Millisecond != 0 {
		Logger.Println("ConsumerConfig.MaxWaitTime only supports millisecond precision; nanoseconds will be truncated.")
	}

	if config.EventBufferSize < 0 {
		return ConfigurationError("Invalid EventBufferSize")
	}

	return nil
}
<|endoftext|>


<commit_before>package incata

import (
	"errors"

	"github.com/mantzas/incata/model"
	"github.com/mantzas/incata/writer"
)

// Appender interface
type Appender interface {
	Append(interface{}) error
}

// EventAppender Append events to storage
type EventAppender struct {
	Writer writer.Writer
}

var wr writer.Writer

// SetupAppender setting up the appender
func SetupAppender(writer writer.Writer) {
	wr = writer
}

// NewAppender Creates a new event appender
func NewAppender() (*EventAppender, error) {

	if wr == nil {
		return nil, errors.New("Writer is not set up!")
	}
	return &EventAppender{Writer: wr}, nil
}

// Append Append the payload to the storage
func (appender *EventAppender) Append(event model.Event) error {

	return appender.Writer.Write(event)
}
<commit_msg>changed interface arguemnt<commit_after>package incata

import (
	"errors"

	"github.com/mantzas/incata/model"
	"github.com/mantzas/incata/writer"
)

// Appender interface
type Appender interface {
	Append(event model.Event) error
}

// EventAppender Append events to storage
type EventAppender struct {
	Writer writer.Writer
}

var wr writer.Writer

// SetupAppender setting up the appender
func SetupAppender(writer writer.Writer) {
	wr = writer
}

// NewAppender Creates a new event appender
func NewAppender() (*EventAppender, error) {

	if wr == nil {
		return nil, errors.New("Writer is not set up!")
	}
	return &EventAppender{Writer: wr}, nil
}

// Append Append the payload to the storage
func (appender *EventAppender) Append(event model.Event) error {

	return appender.Writer.Write(event)
}
<|endoftext|>