<commit_before>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ssa

import (
	"fmt"
	"sort"
)

const (
	cmpDepth = 1
)

// cse does common-subexpression elimination on the Function.
// Values are just relinked, nothing is deleted. A subsequent deadcode
// pass is required to actually remove duplicate expressions.
func cse(f *Func) {
	// Two values are equivalent if they satisfy the following definition:
	// equivalent(v, w):
	//   v.op == w.op
	//   v.type == w.type
	//   v.aux == w.aux
	//   v.auxint == w.auxint
	//   len(v.args) == len(w.args)
	//   v.block == w.block if v.op == OpPhi
	//   equivalent(v.args[i], w.args[i]) for i in 0..len(v.args)-1

	// The algorithm searches for a partition of f's values into
	// equivalence classes using the above definition.
	// It starts with a coarse partition and iteratively refines it
	// until it reaches a fixed point.

	// Make initial coarse partitions by using a subset of the conditions above.
	a := make([]*Value, 0, f.NumValues())
	auxIDs := auxmap{}
	for _, b := range f.Blocks {
		for _, v := range b.Values {
			if auxIDs[v.Aux] == 0 {
				auxIDs[v.Aux] = int32(len(auxIDs)) + 1
			}
			if v.Type.IsMemory() {
				continue // memory values can never cse
			}
			if opcodeTable[v.Op].commutative && len(v.Args) == 2 && v.Args[1].ID < v.Args[0].ID {
				// Order the arguments of binary commutative operations.
				v.Args[0], v.Args[1] = v.Args[1], v.Args[0]
			}
			a = append(a, v)
		}
	}
	partition := partitionValues(a, auxIDs)

	// map from value id back to eqclass id
	valueEqClass := make([]ID, f.NumValues())
	for _, b := range f.Blocks {
		for _, v := range b.Values {
			// Use negative equivalence class #s for unique values.
			valueEqClass[v.ID] = -v.ID
		}
	}
	for i, e := range partition {
		if f.pass.debug > 1 && len(e) > 500 {
			fmt.Printf("CSE.large partition (%d): ", len(e))
			for j := 0; j < 3; j++ {
				fmt.Printf("%s ", e[j].LongString())
			}
			fmt.Println()
		}

		for _, v := range e {
			valueEqClass[v.ID] = ID(i)
		}
		if f.pass.debug > 2 && len(e) > 1 {
			fmt.Printf("CSE.partition #%d:", i)
			for _, v := range e {
				fmt.Printf(" %s", v.String())
			}
			fmt.Printf("\n")
		}
	}

	// Find an equivalence class where some members of the class have
	// non-equivalent arguments. Split the equivalence class appropriately.
	// Repeat until we can't find any more splits.
	for {
		changed := false

		// partition can grow in the loop. By not using a range loop here,
		// we process new additions as they arrive, avoiding O(n^2) behavior.
		for i := 0; i < len(partition); i++ {
			e := partition[i]
			v := e[0]
			// all values in this equiv class that are not equivalent to v get moved
			// into another equiv class.
			// To avoid allocating while building that equivalence class,
			// move the values equivalent to v to the beginning of e
			// and other values to the end of e.
			allvals := e
		eqloop:
			for j := 1; j < len(e); {
				w := e[j]
				equivalent := true
				for i := 0; i < len(v.Args); i++ {
					if valueEqClass[v.Args[i].ID] != valueEqClass[w.Args[i].ID] {
						equivalent = false
						break
					}
				}
				if !equivalent || v.Type.Compare(w.Type) != CMPeq {
					// w is not equivalent to v.
					// move it to the end and shrink e.
					e[j], e[len(e)-1] = e[len(e)-1], e[j]
					e = e[:len(e)-1]
					valueEqClass[w.ID] = ID(len(partition))
					changed = true
					continue eqloop
				}
				// v and w are equivalent. Keep w in e.
				j++
			}
			partition[i] = e
			if len(e) < len(allvals) {
				partition = append(partition, allvals[len(e):])
			}
		}

		if !changed {
			break
		}
	}

	sdom := f.sdom()

	// Compute substitutions we would like to do. We substitute v for w
	// if v and w are in the same equivalence class and v dominates w.
	rewrite := make([]*Value, f.NumValues())
	for _, e := range partition {
		sort.Sort(partitionByDom{e, sdom})
		for i := 0; i < len(e)-1; i++ {
			// e is sorted by domorder, so a maximal dominant element is first in the slice
			v := e[i]
			if v == nil {
				continue
			}

			e[i] = nil
			// Replace all elements of e which v dominates
			for j := i + 1; j < len(e); j++ {
				w := e[j]
				if w == nil {
					continue
				}
				if sdom.isAncestorEq(v.Block, w.Block) {
					rewrite[w.ID] = v
					e[j] = nil
				} else {
					// e is sorted by domorder, so v.Block doesn't dominate any subsequent blocks in e
					break
				}
			}
		}
	}

	// if we rewrite a tuple generator to a new one in a different block,
	// copy its selectors to the new generator's block, so tuple generator
	// and selectors stay together.
	// be careful not to copy same selectors more than once (issue 16741).
	copiedSelects := make(map[ID][]*Value)
	for _, b := range f.Blocks {
	out:
		for _, v := range b.Values {
			if rewrite[v.ID] != nil {
				continue
			}
			if v.Op != OpSelect0 && v.Op != OpSelect1 {
				continue
			}
			if !v.Args[0].Type.IsTuple() {
				f.Fatalf("arg of tuple selector %s is not a tuple: %s", v.String(), v.Args[0].LongString())
			}
			t := rewrite[v.Args[0].ID]
			if t != nil && t.Block != b {
				// v.Args[0] is tuple generator, CSE'd into a different block as t, v is left behind
				for _, c := range copiedSelects[t.ID] {
					if v.Op == c.Op {
						// an equivalent selector is already copied
						rewrite[v.ID] = c
						continue out
					}
				}
				c := v.copyInto(t.Block)
				rewrite[v.ID] = c
				copiedSelects[t.ID] = append(copiedSelects[t.ID], c)
			}
		}
	}

	rewrites := int64(0)

	// Apply substitutions
	for _, b := range f.Blocks {
		for _, v := range b.Values {
			for i, w := range v.Args {
				if x := rewrite[w.ID]; x != nil {
					v.SetArg(i, x)
					rewrites++
				}
			}
		}
		if v := b.Control; v != nil {
			if x := rewrite[v.ID]; x != nil {
				if v.Op == OpNilCheck {
					// nilcheck pass will remove the nil checks and log
					// them appropriately, so don't mess with them here.
					continue
				}
				b.SetControl(x)
			}
		}
	}
	if f.pass.stats > 0 {
		f.LogStat("CSE REWRITES", rewrites)
	}
}

// An eqclass approximates an equivalence class. During the
// algorithm it may represent the union of several of the
// final equivalence classes.
type eqclass []*Value

// partitionValues partitions the values into equivalence classes
// based on having all the following features match:
//  - opcode
//  - type
//  - auxint
//  - aux
//  - nargs
//  - block # if a phi op
//  - first two arg's opcodes and auxint
//  - NOT first two arg's aux; that can break CSE.
// partitionValues returns a list of equivalence classes, each
// being a sorted by ID list of *Values. The eqclass slices are
// backed by the same storage as the input slice.
// Equivalence classes of size 1 are ignored.
func partitionValues(a []*Value, auxIDs auxmap) []eqclass {
	sort.Sort(sortvalues{a, auxIDs})

	var partition []eqclass
	for len(a) > 0 {
		v := a[0]
		j := 1
		for ; j < len(a); j++ {
			w := a[j]
			if cmpVal(v, w, auxIDs, cmpDepth) != CMPeq {
				break
			}
		}
		if j > 1 {
			partition = append(partition, a[:j])
		}
		a = a[j:]
	}

	return partition
}
func lt2Cmp(isLt bool) Cmp {
	if isLt {
		return CMPlt
	}
	return CMPgt
}

type auxmap map[interface{}]int32

func cmpVal(v, w *Value, auxIDs auxmap, depth int) Cmp {
	// Try to order these comparison by cost (cheaper first)
	if v.Op != w.Op {
		return lt2Cmp(v.Op < w.Op)
	}
	if v.AuxInt != w.AuxInt {
		return lt2Cmp(v.AuxInt < w.AuxInt)
	}
	if len(v.Args) != len(w.Args) {
		return lt2Cmp(len(v.Args) < len(w.Args))
	}
	if v.Op == OpPhi && v.Block != w.Block {
		return lt2Cmp(v.Block.ID < w.Block.ID)
	}
	if v.Type.IsMemory() {
		// We will never be able to CSE two values
		// that generate memory.
		return lt2Cmp(v.ID < w.ID)
	}

	if tc := v.Type.Compare(w.Type); tc != CMPeq {
		return tc
	}

	if v.Aux != w.Aux {
		if v.Aux == nil {
			return CMPlt
		}
		if w.Aux == nil {
			return CMPgt
		}
		return lt2Cmp(auxIDs[v.Aux] < auxIDs[w.Aux])
	}

	if depth > 0 {
		for i := range v.Args {
			if v.Args[i] == w.Args[i] {
				// skip comparing equal args
				continue
			}
			if ac := cmpVal(v.Args[i], w.Args[i], auxIDs, depth-1); ac != CMPeq {
				return ac
			}
		}
	}

	return CMPeq
}

// Sort values to make the initial partition.
type sortvalues struct {
	a      []*Value // array of values
	auxIDs auxmap   // aux -> aux ID map
}

func (sv sortvalues) Len() int      { return len(sv.a) }
func (sv sortvalues) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
func (sv sortvalues) Less(i, j int) bool {
	v := sv.a[i]
	w := sv.a[j]
	if cmp := cmpVal(v, w, sv.auxIDs, cmpDepth); cmp != CMPeq {
		return cmp == CMPlt
	}

	// Sort by value ID last to keep the sort result deterministic.
	return v.ID < w.ID
}

type partitionByDom struct {
	a    []*Value // array of values
	sdom SparseTree
}

func (sv partitionByDom) Len() int      { return len(sv.a) }
func (sv partitionByDom) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
func (sv partitionByDom) Less(i, j int) bool {
	v := sv.a[i]
	w := sv.a[j]
	return sv.sdom.domorder(v.Block) < sv.sdom.domorder(w.Block)
}
<commit_msg>cmd/compile: make CSE faster<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ssa

import (
	"fmt"
	"sort"
)

// cse does common-subexpression elimination on the Function.
// Values are just relinked, nothing is deleted. A subsequent deadcode
// pass is required to actually remove duplicate expressions.
func cse(f *Func) {
	// Two values are equivalent if they satisfy the following definition:
	// equivalent(v, w):
	//   v.op == w.op
	//   v.type == w.type
	//   v.aux == w.aux
	//   v.auxint == w.auxint
	//   len(v.args) == len(w.args)
	//   v.block == w.block if v.op == OpPhi
	//   equivalent(v.args[i], w.args[i]) for i in 0..len(v.args)-1

	// The algorithm searches for a partition of f's values into
	// equivalence classes using the above definition.
	// It starts with a coarse partition and iteratively refines it
	// until it reaches a fixed point.

	// Make initial coarse partitions by using a subset of the conditions above.
	a := make([]*Value, 0, f.NumValues())
	auxIDs := auxmap{}
	for _, b := range f.Blocks {
		for _, v := range b.Values {
			if auxIDs[v.Aux] == 0 {
				auxIDs[v.Aux] = int32(len(auxIDs)) + 1
			}
			if v.Type.IsMemory() {
				continue // memory values can never cse
			}
			if opcodeTable[v.Op].commutative && len(v.Args) == 2 && v.Args[1].ID < v.Args[0].ID {
				// Order the arguments of binary commutative operations.
				v.Args[0], v.Args[1] = v.Args[1], v.Args[0]
			}
			a = append(a, v)
		}
	}
	partition := partitionValues(a, auxIDs)

	// map from value id back to eqclass id
	valueEqClass := make([]ID, f.NumValues())
	for _, b := range f.Blocks {
		for _, v := range b.Values {
			// Use negative equivalence class #s for unique values.
			valueEqClass[v.ID] = -v.ID
		}
	}
	var pNum ID = 1
	for _, e := range partition {
		if f.pass.debug > 1 && len(e) > 500 {
			fmt.Printf("CSE.large partition (%d): ", len(e))
			for j := 0; j < 3; j++ {
				fmt.Printf("%s ", e[j].LongString())
			}
			fmt.Println()
		}

		for _, v := range e {
			valueEqClass[v.ID] = pNum
		}
		if f.pass.debug > 2 && len(e) > 1 {
			fmt.Printf("CSE.partition #%d:", pNum)
			for _, v := range e {
				fmt.Printf(" %s", v.String())
			}
			fmt.Printf("\n")
		}
		pNum++
	}

	// Split equivalence classes at points where they have
	// non-equivalent arguments.  Repeat until we can't find any
	// more splits.
	var splitPoints []int
	for {
		changed := false

		// partition can grow in the loop. By not using a range loop here,
		// we process new additions as they arrive, avoiding O(n^2) behavior.
		for i := 0; i < len(partition); i++ {
			e := partition[i]

			// Sort by eq class of arguments.
			sort.Sort(partitionByArgClass{e, valueEqClass})

			// Find split points.
			splitPoints = append(splitPoints[:0], 0)
			for j := 1; j < len(e); j++ {
				v, w := e[j-1], e[j]
				eqArgs := true
				for k, a := range v.Args {
					b := w.Args[k]
					if valueEqClass[a.ID] != valueEqClass[b.ID] {
						eqArgs = false
						break
					}
				}
				if !eqArgs {
					splitPoints = append(splitPoints, j)
				}
			}
			if len(splitPoints) == 1 {
				continue // no splits, leave equivalence class alone.
			}

			// Move another equivalence class down in place of e.
			partition[i] = partition[len(partition)-1]
			partition = partition[:len(partition)-1]
			i--

			// Add new equivalence classes for the parts of e we found.
			splitPoints = append(splitPoints, len(e))
			for j := 0; j < len(splitPoints)-1; j++ {
				f := e[splitPoints[j]:splitPoints[j+1]]
				if len(f) == 1 {
					// Don't add singletons.
					valueEqClass[f[0].ID] = -f[0].ID
					continue
				}
				for _, v := range f {
					valueEqClass[v.ID] = pNum
				}
				pNum++
				partition = append(partition, f)
			}
			changed = true
		}

		if !changed {
			break
		}
	}

	sdom := f.sdom()

	// Compute substitutions we would like to do. We substitute v for w
	// if v and w are in the same equivalence class and v dominates w.
	rewrite := make([]*Value, f.NumValues())
	for _, e := range partition {
		sort.Sort(partitionByDom{e, sdom})
		for i := 0; i < len(e)-1; i++ {
			// e is sorted by domorder, so a maximal dominant element is first in the slice
			v := e[i]
			if v == nil {
				continue
			}

			e[i] = nil
			// Replace all elements of e which v dominates
			for j := i + 1; j < len(e); j++ {
				w := e[j]
				if w == nil {
					continue
				}
				if sdom.isAncestorEq(v.Block, w.Block) {
					rewrite[w.ID] = v
					e[j] = nil
				} else {
					// e is sorted by domorder, so v.Block doesn't dominate any subsequent blocks in e
					break
				}
			}
		}
	}

	// if we rewrite a tuple generator to a new one in a different block,
	// copy its selectors to the new generator's block, so tuple generator
	// and selectors stay together.
	// be careful not to copy same selectors more than once (issue 16741).
	copiedSelects := make(map[ID][]*Value)
	for _, b := range f.Blocks {
	out:
		for _, v := range b.Values {
			if rewrite[v.ID] != nil {
				continue
			}
			if v.Op != OpSelect0 && v.Op != OpSelect1 {
				continue
			}
			if !v.Args[0].Type.IsTuple() {
				f.Fatalf("arg of tuple selector %s is not a tuple: %s", v.String(), v.Args[0].LongString())
			}
			t := rewrite[v.Args[0].ID]
			if t != nil && t.Block != b {
				// v.Args[0] is tuple generator, CSE'd into a different block as t, v is left behind
				for _, c := range copiedSelects[t.ID] {
					if v.Op == c.Op {
						// an equivalent selector is already copied
						rewrite[v.ID] = c
						continue out
					}
				}
				c := v.copyInto(t.Block)
				rewrite[v.ID] = c
				copiedSelects[t.ID] = append(copiedSelects[t.ID], c)
			}
		}
	}

	rewrites := int64(0)

	// Apply substitutions
	for _, b := range f.Blocks {
		for _, v := range b.Values {
			for i, w := range v.Args {
				if x := rewrite[w.ID]; x != nil {
					v.SetArg(i, x)
					rewrites++
				}
			}
		}
		if v := b.Control; v != nil {
			if x := rewrite[v.ID]; x != nil {
				if v.Op == OpNilCheck {
					// nilcheck pass will remove the nil checks and log
					// them appropriately, so don't mess with them here.
					continue
				}
				b.SetControl(x)
			}
		}
	}
	if f.pass.stats > 0 {
		f.LogStat("CSE REWRITES", rewrites)
	}
}

// An eqclass approximates an equivalence class. During the
// algorithm it may represent the union of several of the
// final equivalence classes.
type eqclass []*Value

// partitionValues partitions the values into equivalence classes
// based on having all the following features match:
//  - opcode
//  - type
//  - auxint
//  - aux
//  - nargs
//  - block # if a phi op
//  - first two arg's opcodes and auxint
//  - NOT first two arg's aux; that can break CSE.
// partitionValues returns a list of equivalence classes, each
// being a sorted by ID list of *Values. The eqclass slices are
// backed by the same storage as the input slice.
// Equivalence classes of size 1 are ignored.
func partitionValues(a []*Value, auxIDs auxmap) []eqclass {
	sort.Sort(sortvalues{a, auxIDs})

	var partition []eqclass
	for len(a) > 0 {
		v := a[0]
		j := 1
		for ; j < len(a); j++ {
			w := a[j]
			if cmpVal(v, w, auxIDs) != CMPeq {
				break
			}
		}
		if j > 1 {
			partition = append(partition, a[:j])
		}
		a = a[j:]
	}

	return partition
}
func lt2Cmp(isLt bool) Cmp {
	if isLt {
		return CMPlt
	}
	return CMPgt
}

type auxmap map[interface{}]int32

func cmpVal(v, w *Value, auxIDs auxmap) Cmp {
	// Try to order these comparison by cost (cheaper first)
	if v.Op != w.Op {
		return lt2Cmp(v.Op < w.Op)
	}
	if v.AuxInt != w.AuxInt {
		return lt2Cmp(v.AuxInt < w.AuxInt)
	}
	if len(v.Args) != len(w.Args) {
		return lt2Cmp(len(v.Args) < len(w.Args))
	}
	if v.Op == OpPhi && v.Block != w.Block {
		return lt2Cmp(v.Block.ID < w.Block.ID)
	}
	if v.Type.IsMemory() {
		// We will never be able to CSE two values
		// that generate memory.
		return lt2Cmp(v.ID < w.ID)
	}

	if tc := v.Type.Compare(w.Type); tc != CMPeq {
		return tc
	}

	if v.Aux != w.Aux {
		if v.Aux == nil {
			return CMPlt
		}
		if w.Aux == nil {
			return CMPgt
		}
		return lt2Cmp(auxIDs[v.Aux] < auxIDs[w.Aux])
	}

	return CMPeq
}

// Sort values to make the initial partition.
type sortvalues struct {
	a      []*Value // array of values
	auxIDs auxmap   // aux -> aux ID map
}

func (sv sortvalues) Len() int      { return len(sv.a) }
func (sv sortvalues) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
func (sv sortvalues) Less(i, j int) bool {
	v := sv.a[i]
	w := sv.a[j]
	if cmp := cmpVal(v, w, sv.auxIDs); cmp != CMPeq {
		return cmp == CMPlt
	}

	// Sort by value ID last to keep the sort result deterministic.
	return v.ID < w.ID
}

type partitionByDom struct {
	a    []*Value // array of values
	sdom SparseTree
}

func (sv partitionByDom) Len() int      { return len(sv.a) }
func (sv partitionByDom) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
func (sv partitionByDom) Less(i, j int) bool {
	v := sv.a[i]
	w := sv.a[j]
	return sv.sdom.domorder(v.Block) < sv.sdom.domorder(w.Block)
}

type partitionByArgClass struct {
	a       []*Value // array of values
	eqClass []ID     // equivalence class IDs of values
}

func (sv partitionByArgClass) Len() int      { return len(sv.a) }
func (sv partitionByArgClass) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
func (sv partitionByArgClass) Less(i, j int) bool {
	v := sv.a[i]
	w := sv.a[j]
	for i, a := range v.Args {
		b := w.Args[i]
		if sv.eqClass[a.ID] < sv.eqClass[b.ID] {
			return true
		}
		if sv.eqClass[a.ID] > sv.eqClass[b.ID] {
			return false
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package image

import (
	"testing"
)

func cmp(t *testing.T, cm ColorModel, c0, c1 Color) bool {
	r0, g0, b0, a0 := cm.Convert(c0).RGBA()
	r1, g1, b1, a1 := cm.Convert(c1).RGBA()
	return r0 == r1 && g0 == g1 && b0 == b1 && a0 == a1
}

func TestImage(t *testing.T) {
	type buffered interface {
		Image
		Set(int, int, Color)
		SubImage(Rectangle) Image
	}
	testImage := []Image{
		NewRGBA(10, 10),
		NewRGBA64(10, 10),
		NewNRGBA(10, 10),
		NewNRGBA64(10, 10),
		NewAlpha(10, 10),
		NewAlpha16(10, 10),
		NewGray(10, 10),
		NewGray16(10, 10),
		NewPaletted(10, 10, PalettedColorModel{
			Transparent,
			Opaque,
		}),
	}
	for _, m := range testImage {
		b := m.(buffered)
		if !Rect(0, 0, 10, 10).Eq(b.Bounds()) {
			t.Errorf("%T: want bounds %v, got %v", b, Rect(0, 0, 10, 10), b.Bounds())
			continue
		}
		if !cmp(t, b.ColorModel(), Transparent, b.At(6, 3)) {
			t.Errorf("%T: at (6, 3), want a zero color, got %v", b, b.At(6, 3))
			continue
		}
		b.Set(6, 3, Opaque)
		if !cmp(t, b.ColorModel(), Opaque, b.At(6, 3)) {
			t.Errorf("%T: at (6, 3), want a non-zero color, got %v", b, b.At(6, 3))
			continue
		}
		b = b.SubImage(Rect(3, 2, 9, 8)).(buffered)
		if !Rect(3, 2, 9, 8).Eq(b.Bounds()) {
			t.Errorf("%T: sub-image want bounds %v, got %v", b, Rect(3, 2, 9, 8), b.Bounds())
			continue
		}
		if !cmp(t, b.ColorModel(), Opaque, b.At(6, 3)) {
			t.Errorf("%T: sub-image at (6, 3), want a non-zero color, got %v", b, b.At(6, 3))
			continue
		}
		if !cmp(t, b.ColorModel(), Transparent, b.At(3, 3)) {
			t.Errorf("%T: sub-image at (3, 3), want a zero color, got %v", b, b.At(3, 3))
			continue
		}
		b.Set(3, 3, Opaque)
		if !cmp(t, b.ColorModel(), Opaque, b.At(3, 3)) {
			t.Errorf("%T: sub-image at (3, 3), want a non-zero color, got %v", b, b.At(3, 3))
			continue
		}
	}
}
<commit_msg>image: basic test for the 16-bits-per-color-channel types.<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package image

import (
	"testing"
)

type image interface {
	Image
	Set(int, int, Color)
	SubImage(Rectangle) Image
}

func cmp(t *testing.T, cm ColorModel, c0, c1 Color) bool {
	r0, g0, b0, a0 := cm.Convert(c0).RGBA()
	r1, g1, b1, a1 := cm.Convert(c1).RGBA()
	return r0 == r1 && g0 == g1 && b0 == b1 && a0 == a1
}

func TestImage(t *testing.T) {
	testImage := []image{
		NewRGBA(10, 10),
		NewRGBA64(10, 10),
		NewNRGBA(10, 10),
		NewNRGBA64(10, 10),
		NewAlpha(10, 10),
		NewAlpha16(10, 10),
		NewGray(10, 10),
		NewGray16(10, 10),
		NewPaletted(10, 10, PalettedColorModel{
			Transparent,
			Opaque,
		}),
	}
	for _, m := range testImage {
		if !Rect(0, 0, 10, 10).Eq(m.Bounds()) {
			t.Errorf("%T: want bounds %v, got %v", m, Rect(0, 0, 10, 10), m.Bounds())
			continue
		}
		if !cmp(t, m.ColorModel(), Transparent, m.At(6, 3)) {
			t.Errorf("%T: at (6, 3), want a zero color, got %v", m, m.At(6, 3))
			continue
		}
		m.Set(6, 3, Opaque)
		if !cmp(t, m.ColorModel(), Opaque, m.At(6, 3)) {
			t.Errorf("%T: at (6, 3), want a non-zero color, got %v", m, m.At(6, 3))
			continue
		}
		m = m.SubImage(Rect(3, 2, 9, 8)).(image)
		if !Rect(3, 2, 9, 8).Eq(m.Bounds()) {
			t.Errorf("%T: sub-image want bounds %v, got %v", m, Rect(3, 2, 9, 8), m.Bounds())
			continue
		}
		if !cmp(t, m.ColorModel(), Opaque, m.At(6, 3)) {
			t.Errorf("%T: sub-image at (6, 3), want a non-zero color, got %v", m, m.At(6, 3))
			continue
		}
		if !cmp(t, m.ColorModel(), Transparent, m.At(3, 3)) {
			t.Errorf("%T: sub-image at (3, 3), want a zero color, got %v", m, m.At(3, 3))
			continue
		}
		m.Set(3, 3, Opaque)
		if !cmp(t, m.ColorModel(), Opaque, m.At(3, 3)) {
			t.Errorf("%T: sub-image at (3, 3), want a non-zero color, got %v", m, m.At(3, 3))
			continue
		}
	}
}

func Test16BitsPerColorChannel(t *testing.T) {
	testColorModel := []ColorModel{
		RGBA64ColorModel,
		NRGBA64ColorModel,
		Alpha16ColorModel,
		Gray16ColorModel,
	}
	for _, cm := range testColorModel {
		c := cm.Convert(RGBA64Color{0x1234, 0x1234, 0x1234, 0x1234}) // Premultiplied alpha.
		r, _, _, _ := c.RGBA()
		if r != 0x1234 {
			t.Errorf("%T: want red value 0x%04x got 0x%04x", c, 0x1234, r)
			continue
		}
	}
	testImage := []image{
		NewRGBA64(10, 10),
		NewNRGBA64(10, 10),
		NewAlpha16(10, 10),
		NewGray16(10, 10),
	}
	for _, m := range testImage {
		m.Set(1, 2, NRGBA64Color{0xffff, 0xffff, 0xffff, 0x1357}) // Non-premultiplied alpha.
		r, _, _, _ := m.At(1, 2).RGBA()
		if r != 0x1357 {
			t.Errorf("%T: want red value 0x%04x got 0x%04x", m, 0x1357, r)
			continue
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"testing"
	"runtime"
)

type testCase struct {
	name   string
	result bool
}

var tests = []testCase{
	// RFC2181, section 11.
	{"_xmpp-server._tcp.google.com", true},
	{"_xmpp-server._tcp.google.com", true},
	{"foo.com", true},
	{"1foo.com", true},
	{"26.0.0.73.com", true},
	{"fo-o.com", true},
	{"fo1o.com", true},
	{"foo1.com", true},
	{"a.b..com", false},
}

func getTestCases(ch chan<- *testCase) {
	defer close(ch)
	var char59 = ""
	var char63 = ""
	var char64 = ""
	for i := 0; i < 59; i++ {
		char59 += "a"
	}
	char63 = char59 + "aaaa"
	char64 = char63 + "a"

	for _, tc := range tests {
		ch <- &tc
	}

	ch <- &testCase{char63 + ".com", true}
	ch <- &testCase{char64 + ".com", false}
	// 255 char name is fine:
	ch <- &testCase{char59 + "." + char63 + "." + char63 + "." +
		char63 + ".com",
		true}
	// 256 char name is bad:
	ch <- &testCase{char59 + "a." + char63 + "." + char63 + "." +
		char63 + ".com",
		false}
}

func TestDNSNames(t *testing.T) {
	if runtime.GOOS == "windows" {
		return
	}
	ch := make(chan *testCase)
	go getTestCases(ch)
	for tc := range ch {
		if isDomainName(tc.name) != tc.result {
			t.Errorf("isDomainName(%v) failed: Should be %v",
				tc.name, tc.result)
		}
	}
}
<commit_msg>net: Fix race condition in test.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"testing"
	"runtime"
)

type testCase struct {
	name   string
	result bool
}

var tests = []testCase{
	// RFC2181, section 11.
	{"_xmpp-server._tcp.google.com", true},
	{"_xmpp-server._tcp.google.com", true},
	{"foo.com", true},
	{"1foo.com", true},
	{"26.0.0.73.com", true},
	{"fo-o.com", true},
	{"fo1o.com", true},
	{"foo1.com", true},
	{"a.b..com", false},
}

func getTestCases(ch chan<- testCase) {
	defer close(ch)
	var char59 = ""
	var char63 = ""
	var char64 = ""
	for i := 0; i < 59; i++ {
		char59 += "a"
	}
	char63 = char59 + "aaaa"
	char64 = char63 + "a"

	for _, tc := range tests {
		ch <- tc
	}

	ch <- testCase{char63 + ".com", true}
	ch <- testCase{char64 + ".com", false}
	// 255 char name is fine:
	ch <- testCase{char59 + "." + char63 + "." + char63 + "." +
		char63 + ".com",
		true}
	// 256 char name is bad:
	ch <- testCase{char59 + "a." + char63 + "." + char63 + "." +
		char63 + ".com",
		false}
}

func TestDNSNames(t *testing.T) {
	if runtime.GOOS == "windows" {
		return
	}
	ch := make(chan testCase)
	go getTestCases(ch)
	for tc := range ch {
		if isDomainName(tc.name) != tc.result {
			t.Errorf("isDomainName(%v) failed: Should be %v",
				tc.name, tc.result)
		}
	}
}
<|endoftext|>


<commit_before>// Package dirwatch provides filesystem-notification based tracking of torrent
// info files and magnet URIs in a directory.
package dirwatch

import (
	"bufio"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/anacrolix/missinggo"
	"github.com/go-fsnotify/fsnotify"

	"github.com/anacrolix/torrent/metainfo"
)

type Change uint

const (
	Added Change = iota
	Removed
)

type Event struct {
	MagnetURI string
	Change
	TorrentFilePath string
	InfoHash        metainfo.Hash
}

type entity struct {
	metainfo.Hash
	MagnetURI       string
	TorrentFilePath string
}

type Instance struct {
	w        *fsnotify.Watcher
	dirName  string
	Events   chan Event
	dirState map[metainfo.Hash]entity
}

func (i *Instance) Close() {
	i.w.Close()
}

func (i *Instance) handleEvents() {
	defer close(i.Events)
	for e := range i.w.Events {
		log.Printf("event: %s", e)
		if e.Op == fsnotify.Write {
			// TODO: Special treatment as an existing torrent may have changed.
		} else {
			i.refresh()
		}
	}
}

func (i *Instance) handleErrors() {
	for err := range i.w.Errors {
		log.Printf("error in torrent directory watcher: %s", err)
	}
}

func torrentFileInfoHash(fileName string) (ih metainfo.Hash, ok bool) {
	mi, _ := metainfo.LoadFromFile(fileName)
	if mi == nil {
		return
	}
	ih = mi.HashInfoBytes()
	ok = true
	return
}

func scanDir(dirName string) (ee map[metainfo.Hash]entity) {
	d, err := os.Open(dirName)
	if err != nil {
		log.Print(err)
		return
	}
	defer d.Close()
	names, err := d.Readdirnames(-1)
	if err != nil {
		log.Print(err)
		return
	}
	ee = make(map[metainfo.Hash]entity, len(names))
	addEntity := func(e entity) {
		e0, ok := ee[e.Hash]
		if ok {
			if e0.MagnetURI == "" || len(e.MagnetURI) < len(e0.MagnetURI) {
				return
			}
		}
		ee[e.Hash] = e
	}
	for _, n := range names {
		fullName := filepath.Join(dirName, n)
		switch filepath.Ext(n) {
		case ".torrent":
			ih, ok := torrentFileInfoHash(fullName)
			if !ok {
				break
			}
			e := entity{
				TorrentFilePath: fullName,
			}
			missinggo.CopyExact(&e.Hash, ih)
			addEntity(e)
		case ".magnet":
			uris, err := magnetFileURIs(fullName)
			if err != nil {
				log.Print(err)
				break
			}
			for _, uri := range uris {
				m, err := metainfo.ParseMagnetURI(uri)
				if err != nil {
					log.Printf("error parsing %q in file %q: %s", uri, fullName, err)
					continue
				}
				addEntity(entity{
					Hash:      m.InfoHash,
					MagnetURI: uri,
				})
			}
		}
	}
	return
}

func magnetFileURIs(name string) (uris []string, err error) {
	f, err := os.Open(name)
	if err != nil {
		return
	}
	defer f.Close()
	scanner := bufio.NewScanner(f)
	scanner.Split(bufio.ScanWords)
	for scanner.Scan() {
		// Allow magnet URIs to be "commented" out.
		if strings.HasPrefix(scanner.Text(), "#") {
			continue
		}
		uris = append(uris, scanner.Text())
	}
	err = scanner.Err()
	return
}

func (i *Instance) torrentRemoved(ih metainfo.Hash) {
	i.Events <- Event{
		InfoHash: ih,
		Change:   Removed,
	}
}

func (i *Instance) torrentAdded(e entity) {
	i.Events <- Event{
		InfoHash:        e.Hash,
		Change:          Added,
		MagnetURI:       e.MagnetURI,
		TorrentFilePath: e.TorrentFilePath,
	}
}

func (i *Instance) refresh() {
	_new := scanDir(i.dirName)
	old := i.dirState
	for ih := range old {
		_, ok := _new[ih]
		if !ok {
			i.torrentRemoved(ih)
		}
	}
	for ih, newE := range _new {
		oldE, ok := old[ih]
		if ok {
			if newE == oldE {
				continue
			}
			i.torrentRemoved(ih)
		}
		i.torrentAdded(newE)
	}
	i.dirState = _new
}

func New(dirName string) (i *Instance, err error) {
	w, err := fsnotify.NewWatcher()
	if err != nil {
		return
	}
	err = w.Add(dirName)
	if err != nil {
		w.Close()
		return
	}
	i = &Instance{
		w:        w,
		dirName:  dirName,
		Events:   make(chan Event),
		dirState: make(map[metainfo.Hash]entity, 0),
	}
	go func() {
		i.refresh()
		go i.handleEvents()
		go i.handleErrors()
	}()
	return
}
<commit_msg>github.com/go-fsnotify/fsnotify -> github.com/fsnotify/fsnotify<commit_after>// Package dirwatch provides filesystem-notification based tracking of torrent
// info files and magnet URIs in a directory.
package dirwatch

import (
	"bufio"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/anacrolix/missinggo"
	"github.com/fsnotify/fsnotify"

	"github.com/anacrolix/torrent/metainfo"
)

type Change uint

const (
	Added Change = iota
	Removed
)

type Event struct {
	MagnetURI string
	Change
	TorrentFilePath string
	InfoHash        metainfo.Hash
}

type entity struct {
	metainfo.Hash
	MagnetURI       string
	TorrentFilePath string
}

type Instance struct {
	w        *fsnotify.Watcher
	dirName  string
	Events   chan Event
	dirState map[metainfo.Hash]entity
}

func (i *Instance) Close() {
	i.w.Close()
}

func (i *Instance) handleEvents() {
	defer close(i.Events)
	for e := range i.w.Events {
		log.Printf("event: %s", e)
		if e.Op == fsnotify.Write {
			// TODO: Special treatment as an existing torrent may have changed.
		} else {
			i.refresh()
		}
	}
}

func (i *Instance) handleErrors() {
	for err := range i.w.Errors {
		log.Printf("error in torrent directory watcher: %s", err)
	}
}

func torrentFileInfoHash(fileName string) (ih metainfo.Hash, ok bool) {
	mi, _ := metainfo.LoadFromFile(fileName)
	if mi == nil {
		return
	}
	ih = mi.HashInfoBytes()
	ok = true
	return
}

func scanDir(dirName string) (ee map[metainfo.Hash]entity) {
	d, err := os.Open(dirName)
	if err != nil {
		log.Print(err)
		return
	}
	defer d.Close()
	names, err := d.Readdirnames(-1)
	if err != nil {
		log.Print(err)
		return
	}
	ee = make(map[metainfo.Hash]entity, len(names))
	addEntity := func(e entity) {
		e0, ok := ee[e.Hash]
		if ok {
			if e0.MagnetURI == "" || len(e.MagnetURI) < len(e0.MagnetURI) {
				return
			}
		}
		ee[e.Hash] = e
	}
	for _, n := range names {
		fullName := filepath.Join(dirName, n)
		switch filepath.Ext(n) {
		case ".torrent":
			ih, ok := torrentFileInfoHash(fullName)
			if !ok {
				break
			}
			e := entity{
				TorrentFilePath: fullName,
			}
			missinggo.CopyExact(&e.Hash, ih)
			addEntity(e)
		case ".magnet":
			uris, err := magnetFileURIs(fullName)
			if err != nil {
				log.Print(err)
				break
			}
			for _, uri := range uris {
				m, err := metainfo.ParseMagnetURI(uri)
				if err != nil {
					log.Printf("error parsing %q in file %q: %s", uri, fullName, err)
					continue
				}
				addEntity(entity{
					Hash:      m.InfoHash,
					MagnetURI: uri,
				})
			}
		}
	}
	return
}

func magnetFileURIs(name string) (uris []string, err error) {
	f, err := os.Open(name)
	if err != nil {
		return
	}
	defer f.Close()
	scanner := bufio.NewScanner(f)
	scanner.Split(bufio.ScanWords)
	for scanner.Scan() {
		// Allow magnet URIs to be "commented" out.
		if strings.HasPrefix(scanner.Text(), "#") {
			continue
		}
		uris = append(uris, scanner.Text())
	}
	err = scanner.Err()
	return
}

func (i *Instance) torrentRemoved(ih metainfo.Hash) {
	i.Events <- Event{
		InfoHash: ih,
		Change:   Removed,
	}
}

func (i *Instance) torrentAdded(e entity) {
	i.Events <- Event{
		InfoHash:        e.Hash,
		Change:          Added,
		MagnetURI:       e.MagnetURI,
		TorrentFilePath: e.TorrentFilePath,
	}
}

func (i *Instance) refresh() {
	_new := scanDir(i.dirName)
	old := i.dirState
	for ih := range old {
		_, ok := _new[ih]
		if !ok {
			i.torrentRemoved(ih)
		}
	}
	for ih, newE := range _new {
		oldE, ok := old[ih]
		if ok {
			if newE == oldE {
				continue
			}
			i.torrentRemoved(ih)
		}
		i.torrentAdded(newE)
	}
	i.dirState = _new
}

func New(dirName string) (i *Instance, err error) {
	w, err := fsnotify.NewWatcher()
	if err != nil {
		return
	}
	err = w.Add(dirName)
	if err != nil {
		w.Close()
		return
	}
	i = &Instance{
		w:        w,
		dirName:  dirName,
		Events:   make(chan Event),
		dirState: make(map[metainfo.Hash]entity, 0),
	}
	go func() {
		i.refresh()
		go i.handleEvents()
		go i.handleErrors()
	}()
	return
}
<|endoftext|>


<commit_before>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package leaktest provides tools to detect leaked goroutines in tests.
// To use it, call "defer leaktest.AfterTest(t)()" at the beginning of each
// test that may use goroutines.
package leaktest

import (
	"runtime"
	"sort"
	"strings"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/util/timeutil"
)

// interestingGoroutines returns all goroutines we care about for the purpose
// of leak checking. It excludes testing or runtime ones.
func interestingGoroutines() (gs []string) {
	buf := make([]byte, 2<<20)
	buf = buf[:runtime.Stack(buf, true)]
	for _, g := range strings.Split(string(buf), "\n\n") {
		sl := strings.SplitN(g, "\n", 2)
		if len(sl) != 2 {
			continue
		}
		stack := strings.TrimSpace(sl[1])
		if strings.HasPrefix(stack, "testing.RunTests") {
			continue
		}

		if stack == "" ||
			strings.Contains(stack, "github.com/cockroachdb/cockroach/util/log.init") ||
			// Go1.7 added a goroutine to network dialing that doesn't shut down
			// quickly.
			strings.Contains(stack, "created by net.(*netFD).connect") ||
			// Below are the stacks ignored by the upstream leaktest code.
			strings.Contains(stack, "testing.Main(") ||
			strings.Contains(stack, "testing.tRunner(") ||
			strings.Contains(stack, "runtime.goexit") ||
			strings.Contains(stack, "created by runtime.gc") ||
			strings.Contains(stack, "interestingGoroutines") ||
			strings.Contains(stack, "runtime.MHeap_Scavenger") ||
			strings.Contains(stack, "signal.signal_recv") ||
			strings.Contains(stack, "sigterm.handler") ||
			strings.Contains(stack, "runtime_mcall") ||
			strings.Contains(stack, "goroutine in C code") {
			continue
		}
		gs = append(gs, g)
	}
	sort.Strings(gs)
	return
}

// AfterTest snapshots the currently-running goroutines and returns a
// function to be run at the end of tests to see whether any
// goroutines leaked.
func AfterTest(t testing.TB) func() {
	orig := map[string]bool{}
	for _, g := range interestingGoroutines() {
		orig[g] = true
	}
	return func() {
		if t.Failed() {
			return
		}
		if r := recover(); r != nil {
			panic(r)
		}
		// Loop, waiting for goroutines to shut down.
		// Wait up to 5 seconds, but finish as quickly as possible.
		deadline := timeutil.Now().Add(5 * time.Second)
		for {
			var leaked []string
			for _, g := range interestingGoroutines() {
				if !orig[g] {
					leaked = append(leaked, g)
				}
			}
			if len(leaked) == 0 {
				return
			}
			if timeutil.Now().Before(deadline) {
				time.Sleep(50 * time.Millisecond)
				continue
			}
			for _, g := range leaked {
				t.Errorf("Leaked goroutine: %v", g)
			}
			return
		}
	}
}
<commit_msg>leaktest: Allow goroutines related to the CPU profiler<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package leaktest provides tools to detect leaked goroutines in tests.
// To use it, call "defer leaktest.AfterTest(t)()" at the beginning of each
// test that may use goroutines.
package leaktest

import (
	"runtime"
	"sort"
	"strings"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/util/timeutil"
)

// interestingGoroutines returns all goroutines we care about for the purpose
// of leak checking. It excludes testing or runtime ones.
func interestingGoroutines() (gs []string) {
	buf := make([]byte, 2<<20)
	buf = buf[:runtime.Stack(buf, true)]
	for _, g := range strings.Split(string(buf), "\n\n") {
		sl := strings.SplitN(g, "\n", 2)
		if len(sl) != 2 {
			continue
		}
		stack := strings.TrimSpace(sl[1])
		if strings.HasPrefix(stack, "testing.RunTests") {
			continue
		}

		if stack == "" ||
			strings.Contains(stack, "github.com/cockroachdb/cockroach/util/log.init") ||
			// Go1.7 added a goroutine to network dialing that doesn't shut down
			// quickly.
			strings.Contains(stack, "created by net.(*netFD).connect") ||
			// Below are the stacks ignored by the upstream leaktest code.
			strings.Contains(stack, "testing.Main(") ||
			strings.Contains(stack, "testing.tRunner(") ||
			strings.Contains(stack, "runtime.goexit") ||
			strings.Contains(stack, "created by runtime.gc") ||
			strings.Contains(stack, "interestingGoroutines") ||
			strings.Contains(stack, "runtime.MHeap_Scavenger") ||
			strings.Contains(stack, "signal.signal_recv") ||
			strings.Contains(stack, "sigterm.handler") ||
			strings.Contains(stack, "runtime_mcall") ||
			strings.Contains(stack, "goroutine in C code") ||
			strings.Contains(stack, "runtime.CPUProfile") {
			continue
		}
		gs = append(gs, g)
	}
	sort.Strings(gs)
	return
}

// AfterTest snapshots the currently-running goroutines and returns a
// function to be run at the end of tests to see whether any
// goroutines leaked.
func AfterTest(t testing.TB) func() {
	orig := map[string]bool{}
	for _, g := range interestingGoroutines() {
		orig[g] = true
	}
	return func() {
		if t.Failed() {
			return
		}
		if r := recover(); r != nil {
			panic(r)
		}
		// Loop, waiting for goroutines to shut down.
		// Wait up to 5 seconds, but finish as quickly as possible.
		deadline := timeutil.Now().Add(5 * time.Second)
		for {
			var leaked []string
			for _, g := range interestingGoroutines() {
				if !orig[g] {
					leaked = append(leaked, g)
				}
			}
			if len(leaked) == 0 {
				return
			}
			if timeutil.Now().Before(deadline) {
				time.Sleep(50 * time.Millisecond)
				continue
			}
			for _, g := range leaked {
				t.Errorf("Leaked goroutine: %v", g)
			}
			return
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"fmt"
	"runtime"
	"testing"
	"time"
)

func testTimeout(t *testing.T, net, addr string, readFrom bool) {
	c, err := Dial(net, addr)
	if err != nil {
		t.Errorf("Dial(%q, %q) failed: %v", net, addr, err)
		return
	}
	defer c.Close()
	what := "Read"
	if readFrom {
		what = "ReadFrom"
	}

	errc := make(chan error, 1)
	go func() {
		t0 := time.Now()
		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
		var b [100]byte
		var n int
		var err error
		if readFrom {
			n, _, err = c.(PacketConn).ReadFrom(b[0:])
		} else {
			n, err = c.Read(b[0:])
		}
		t1 := time.Now()
		if n != 0 || err == nil || !err.(Error).Timeout() {
			errc <- fmt.Errorf("%s(%q, %q) did not return 0, timeout: %v, %v", what, net, addr, n, err)
			return
		}
		if dt := t1.Sub(t0); dt < 50*time.Millisecond || !testing.Short() && dt > 250*time.Millisecond {
			errc <- fmt.Errorf("%s(%q, %q) took %s, expected 0.1s", what, net, addr, dt)
			return
		}
		errc <- nil
	}()
	select {
	case err := <-errc:
		if err != nil {
			t.Error(err)
		}
	case <-time.After(1 * time.Second):
		t.Errorf("%s(%q, %q) took over 1 second, expected 0.1s", what, net, addr)
	}
}

func TestTimeoutUDP(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	}

	// set up a listener that won't talk back
	listening := make(chan string)
	done := make(chan int)
	go runDatagramPacketConnServer(t, "udp", "127.0.0.1:0", listening, done)
	addr := <-listening

	testTimeout(t, "udp", addr, false)
	testTimeout(t, "udp", addr, true)
	<-done
}

func TestTimeoutTCP(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	}

	// set up a listener that won't talk back
	listening := make(chan string)
	done := make(chan int)
	go runStreamConnServer(t, "tcp", "127.0.0.1:0", listening, done)
	addr := <-listening

	testTimeout(t, "tcp", addr, false)
	<-done
}

func TestDeadlineReset(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	}
	ln, err := Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer ln.Close()
	tl := ln.(*TCPListener)
	tl.SetDeadline(time.Now().Add(1 * time.Minute))
	tl.SetDeadline(time.Time{}) // reset it
	errc := make(chan error, 1)
	go func() {
		_, err := ln.Accept()
		errc <- err
	}()
	select {
	case <-time.After(50 * time.Millisecond):
		// Pass.
	case err := <-errc:
		// Accept should never return; we never
		// connected to it.
		t.Errorf("unexpected return from Accept; err=%v", err)
	}
}

func TestTimeoutAccept(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	}
	ln, err := Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer ln.Close()
	tl := ln.(*TCPListener)
	tl.SetDeadline(time.Now().Add(100 * time.Millisecond))
	errc := make(chan error, 1)
	go func() {
		_, err := ln.Accept()
		errc <- err
	}()
	select {
	case <-time.After(1 * time.Second):
		// Accept shouldn't block indefinitely
		t.Errorf("Accept didn't return in an expected time")
	case <-errc:
		// Pass.
	}
}

func TestReadWriteDeadline(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	}

	if !canCancelIO {
		t.Logf("skipping test on this system")
		return
	}
	const (
		readTimeout  = 50 * time.Millisecond
		writeTimeout = 250 * time.Millisecond
	)
	checkTimeout := func(command string, start time.Time, should time.Duration) {
		is := time.Now().Sub(start)
		d := should - is
		if d < -30*time.Millisecond || !testing.Short() && 150*time.Millisecond < d {
			t.Errorf("%s timeout test failed: is=%v should=%v\n", command, is, should)
		}
	}

	ln, err := Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("ListenTCP on :0: %v", err)
	}

	lnquit := make(chan bool)

	go func() {
		c, err := ln.Accept()
		if err != nil {
			t.Fatalf("Accept: %v", err)
		}
		defer c.Close()
		lnquit <- true
	}()

	c, err := Dial("tcp", ln.Addr().String())
	if err != nil {
		t.Fatalf("Dial: %v", err)
	}
	defer c.Close()

	start := time.Now()
	err = c.SetReadDeadline(start.Add(readTimeout))
	if err != nil {
		t.Fatalf("SetReadDeadline: %v", err)
	}
	err = c.SetWriteDeadline(start.Add(writeTimeout))
	if err != nil {
		t.Fatalf("SetWriteDeadline: %v", err)
	}

	quit := make(chan bool)

	go func() {
		var buf [10]byte
		_, err := c.Read(buf[:])
		if err == nil {
			t.Errorf("Read should not succeed")
		}
		checkTimeout("Read", start, readTimeout)
		quit <- true
	}()

	go func() {
		var buf [10000]byte
		for {
			_, err := c.Write(buf[:])
			if err != nil {
				break
			}
		}
		checkTimeout("Write", start, writeTimeout)
		quit <- true
	}()

	<-quit
	<-quit
	<-lnquit
}
<commit_msg>net: fix timeout slack calculation<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"fmt"
	"runtime"
	"testing"
	"time"
)

func testTimeout(t *testing.T, net, addr string, readFrom bool) {
	c, err := Dial(net, addr)
	if err != nil {
		t.Errorf("Dial(%q, %q) failed: %v", net, addr, err)
		return
	}
	defer c.Close()
	what := "Read"
	if readFrom {
		what = "ReadFrom"
	}

	errc := make(chan error, 1)
	go func() {
		t0 := time.Now()
		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
		var b [100]byte
		var n int
		var err error
		if readFrom {
			n, _, err = c.(PacketConn).ReadFrom(b[0:])
		} else {
			n, err = c.Read(b[0:])
		}
		t1 := time.Now()
		if n != 0 || err == nil || !err.(Error).Timeout() {
			errc <- fmt.Errorf("%s(%q, %q) did not return 0, timeout: %v, %v", what, net, addr, n, err)
			return
		}
		if dt := t1.Sub(t0); dt < 50*time.Millisecond || !testing.Short() && dt > 250*time.Millisecond {
			errc <- fmt.Errorf("%s(%q, %q) took %s, expected 0.1s", what, net, addr, dt)
			return
		}
		errc <- nil
	}()
	select {
	case err := <-errc:
		if err != nil {
			t.Error(err)
		}
	case <-time.After(1 * time.Second):
		t.Errorf("%s(%q, %q) took over 1 second, expected 0.1s", what, net, addr)
	}
}

func TestTimeoutUDP(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	}

	// set up a listener that won't talk back
	listening := make(chan string)
	done := make(chan int)
	go runDatagramPacketConnServer(t, "udp", "127.0.0.1:0", listening, done)
	addr := <-listening

	testTimeout(t, "udp", addr, false)
	testTimeout(t, "udp", addr, true)
	<-done
}

func TestTimeoutTCP(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	}

	// set up a listener that won't talk back
	listening := make(chan string)
	done := make(chan int)
	go runStreamConnServer(t, "tcp", "127.0.0.1:0", listening, done)
	addr := <-listening

	testTimeout(t, "tcp", addr, false)
	<-done
}

func TestDeadlineReset(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	}
	ln, err := Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer ln.Close()
	tl := ln.(*TCPListener)
	tl.SetDeadline(time.Now().Add(1 * time.Minute))
	tl.SetDeadline(time.Time{}) // reset it
	errc := make(chan error, 1)
	go func() {
		_, err := ln.Accept()
		errc <- err
	}()
	select {
	case <-time.After(50 * time.Millisecond):
		// Pass.
	case err := <-errc:
		// Accept should never return; we never
		// connected to it.
		t.Errorf("unexpected return from Accept; err=%v", err)
	}
}

func TestTimeoutAccept(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	}
	ln, err := Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer ln.Close()
	tl := ln.(*TCPListener)
	tl.SetDeadline(time.Now().Add(100 * time.Millisecond))
	errc := make(chan error, 1)
	go func() {
		_, err := ln.Accept()
		errc <- err
	}()
	select {
	case <-time.After(1 * time.Second):
		// Accept shouldn't block indefinitely
		t.Errorf("Accept didn't return in an expected time")
	case <-errc:
		// Pass.
	}
}

func TestReadWriteDeadline(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	}

	if !canCancelIO {
		t.Logf("skipping test on this system")
		return
	}
	const (
		readTimeout  = 50 * time.Millisecond
		writeTimeout = 250 * time.Millisecond
	)
	checkTimeout := func(command string, start time.Time, should time.Duration) {
		is := time.Now().Sub(start)
		d := is - should
		if d < -30*time.Millisecond || !testing.Short() && 150*time.Millisecond < d {
			t.Errorf("%s timeout test failed: is=%v should=%v\n", command, is, should)
		}
	}

	ln, err := Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("ListenTCP on :0: %v", err)
	}

	lnquit := make(chan bool)

	go func() {
		c, err := ln.Accept()
		if err != nil {
			t.Fatalf("Accept: %v", err)
		}
		defer c.Close()
		lnquit <- true
	}()

	c, err := Dial("tcp", ln.Addr().String())
	if err != nil {
		t.Fatalf("Dial: %v", err)
	}
	defer c.Close()

	start := time.Now()
	err = c.SetReadDeadline(start.Add(readTimeout))
	if err != nil {
		t.Fatalf("SetReadDeadline: %v", err)
	}
	err = c.SetWriteDeadline(start.Add(writeTimeout))
	if err != nil {
		t.Fatalf("SetWriteDeadline: %v", err)
	}

	quit := make(chan bool)

	go func() {
		var buf [10]byte
		_, err := c.Read(buf[:])
		if err == nil {
			t.Errorf("Read should not succeed")
		}
		checkTimeout("Read", start, readTimeout)
		quit <- true
	}()

	go func() {
		var buf [10000]byte
		for {
			_, err := c.Write(buf[:])
			if err != nil {
				break
			}
		}
		checkTimeout("Write", start, writeTimeout)
		quit <- true
	}()

	<-quit
	<-quit
	<-lnquit
}
<|endoftext|>


<commit_before>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package os

import "syscall"

func isExist(err error) bool {
	if pe, ok := err.(*PathError); ok {
		err = pe.Err
	}
	return err == syscall.ERROR_ALREADY_EXISTS ||
		err == syscall.ERROR_FILE_EXISTS || err == ErrExist
}

func isNotExist(err error) bool {
	if pe, ok := err.(*PathError); ok {
		err = pe.Err
	}
	return err == syscall.ERROR_FILE_NOT_FOUND ||
		err == syscall.ERROR_PATH_NOT_FOUND || err == ErrNotExist
}

func isPermission(err error) bool {
	if pe, ok := err.(*PathError); ok {
		err = pe.Err
	}
	return err == ErrPermission
}
<commit_msg>os: fix IsPermission on windows<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package os

import "syscall"

func isExist(err error) bool {
	if pe, ok := err.(*PathError); ok {
		err = pe.Err
	}
	return err == syscall.ERROR_ALREADY_EXISTS ||
		err == syscall.ERROR_FILE_EXISTS || err == ErrExist
}

func isNotExist(err error) bool {
	if pe, ok := err.(*PathError); ok {
		err = pe.Err
	}
	return err == syscall.ERROR_FILE_NOT_FOUND ||
		err == syscall.ERROR_PATH_NOT_FOUND || err == ErrNotExist
}

func isPermission(err error) bool {
	if pe, ok := err.(*PathError); ok {
		err = pe.Err
	}
	return err == syscall.ERROR_ACCESS_DENIED || err == ErrPermission
}
<|endoftext|>


<commit_before>package resolver

import (
	"crypto/tls"
	"crypto/x509"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/containerd/containerd/remotes"
	"github.com/containerd/containerd/remotes/docker"
	"github.com/moby/buildkit/cmd/buildkitd/config"
	"github.com/moby/buildkit/session"
	"github.com/moby/buildkit/session/auth"
	"github.com/moby/buildkit/util/tracing"
	"github.com/pkg/errors"
)

func fillInsecureOpts(host string, c config.RegistryConfig, h *docker.RegistryHost) error {
	tc, err := loadTLSConfig(c)
	if err != nil {
		return err
	}

	if c.PlainHTTP != nil && *c.PlainHTTP {
		h.Scheme = "http"
	} else if c.Insecure != nil && *c.Insecure {
		tc.InsecureSkipVerify = true
	} else if c.PlainHTTP == nil {
		if ok, _ := docker.MatchLocalhost(host); ok {
			h.Scheme = "http"
		}
	}

	transport := newDefaultTransport()
	transport.TLSClientConfig = tc

	h.Client = &http.Client{
		Transport: tracing.NewTransport(transport),
	}
	return nil
}

func loadTLSConfig(c config.RegistryConfig) (*tls.Config, error) {
	for _, d := range c.TLSConfigDir {
		fs, err := ioutil.ReadDir(d)
		if err != nil && !errors.Is(err, os.ErrNotExist) && !errors.Is(err, os.ErrPermission) {
			return nil, errors.WithStack(err)
		}
		for _, f := range fs {
			if strings.HasSuffix(f.Name(), ".crt") {
				c.RootCAs = append(c.RootCAs, filepath.Join(d, f.Name()))
			}
			if strings.HasSuffix(f.Name(), ".cert") {
				c.KeyPairs = append(c.KeyPairs, config.TLSKeyPair{
					Certificate: filepath.Join(d, f.Name()),
					Key:         filepath.Join(d, strings.TrimSuffix(f.Name(), ".cert")+".key"),
				})
			}
		}
	}

	tc := &tls.Config{}
	if len(c.RootCAs) > 0 {
		systemPool, err := x509.SystemCertPool()
		if err != nil {
			if runtime.GOOS == "windows" {
				systemPool = x509.NewCertPool()
			} else {
				return nil, errors.Wrapf(err, "unable to get system cert pool")
			}
		}
		tc.RootCAs = systemPool
	}

	for _, p := range c.RootCAs {
		dt, err := ioutil.ReadFile(p)
		if err != nil {
			return nil, errors.Wrapf(err, "failed to read %s", p)
		}
		tc.RootCAs.AppendCertsFromPEM(dt)
	}

	for _, kp := range c.KeyPairs {
		cert, err := tls.LoadX509KeyPair(kp.Certificate, kp.Key)
		if err != nil {
			return nil, errors.Wrapf(err, "failed to load keypair for %s", kp.Certificate)
		}
		tc.Certificates = append(tc.Certificates, cert)
	}
	return tc, nil
}

func NewRegistryConfig(m map[string]config.RegistryConfig) docker.RegistryHosts {
	return docker.Registries(
		func(host string) ([]docker.RegistryHost, error) {
			c, ok := m[host]
			if !ok {
				return nil, nil
			}

			var out []docker.RegistryHost

			for _, mirror := range c.Mirrors {
				h := docker.RegistryHost{
					Scheme:       "https",
					Client:       newDefaultClient(),
					Host:         mirror,
					Path:         "/v2",
					Capabilities: docker.HostCapabilityPull | docker.HostCapabilityResolve,
				}

				if err := fillInsecureOpts(mirror, m[mirror], &h); err != nil {
					return nil, err
				}

				out = append(out, h)
			}

			if host == "docker.io" {
				host = "registry-1.docker.io"
			}

			h := docker.RegistryHost{
				Scheme:       "https",
				Client:       newDefaultClient(),
				Host:         host,
				Path:         "/v2",
				Capabilities: docker.HostCapabilityPush | docker.HostCapabilityPull | docker.HostCapabilityResolve,
			}

			if err := fillInsecureOpts(host, c, &h); err != nil {
				return nil, err
			}

			out = append(out, h)
			return out, nil
		},
		docker.ConfigureDefaultRegistries(
			docker.WithClient(newDefaultClient()),
			docker.WithPlainHTTP(docker.MatchLocalhost),
		),
	)
}

type SessionAuthenticator struct {
	sm     *session.Manager
	groups []session.Group
	mu     sync.RWMutex
}

func NewSessionAuthenticator(sm *session.Manager, g session.Group) *SessionAuthenticator {
	return &SessionAuthenticator{sm: sm, groups: []session.Group{g}}
}

func (a *SessionAuthenticator) credentials(h string) (string, string, error) {
	a.mu.RLock()
	defer a.mu.RUnlock()

	var err error
	for i := len(a.groups) - 1; i >= 0; i-- {
		var user, secret string
		user, secret, err = auth.CredentialsFunc(a.sm, a.groups[i])(h)
		if err != nil {
			continue
		}
		return user, secret, nil
	}
	return "", "", err
}

func (a *SessionAuthenticator) AddSession(g session.Group) {
	a.mu.Lock()
	a.groups = append(a.groups, g)
	a.mu.Unlock()
}

func New(hosts docker.RegistryHosts, auth *SessionAuthenticator) remotes.Resolver {
	return docker.NewResolver(docker.ResolverOptions{
		Hosts: hostsWithCredentials(hosts, auth),
	})
}

func hostsWithCredentials(hosts docker.RegistryHosts, auth *SessionAuthenticator) docker.RegistryHosts {
	if hosts == nil {
		return nil
	}
	return func(domain string) ([]docker.RegistryHost, error) {
		res, err := hosts(domain)
		if err != nil {
			return nil, err
		}
		if len(res) == 0 {
			return nil, nil
		}

		a := docker.NewDockerAuthorizer(
			docker.WithAuthClient(res[0].Client),
			docker.WithAuthCreds(auth.credentials),
		)
		for i := range res {
			res[i].Authorizer = a
		}
		return res, nil
	}
}

func newDefaultClient() *http.Client {
	return &http.Client{
		Transport: newDefaultTransport(),
	}
}

// newDefaultTransport is for pull or push client
//
// NOTE: For push, there must disable http2 for https because the flow control
// will limit data transfer. The net/http package doesn't provide http2 tunable
// settings which limits push performance.
//
// REF: https://github.com/golang/go/issues/14077
func newDefaultTransport() *http.Transport {
	return &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).DialContext,
		MaxIdleConns:          10,
		IdleConnTimeout:       30 * time.Second,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 5 * time.Second,
		DisableKeepAlives:     true,
		TLSNextProto:          make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
	}
}
<commit_msg>resolver: add credentials cache<commit_after>package resolver

import (
	"crypto/tls"
	"crypto/x509"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/containerd/containerd/remotes"
	"github.com/containerd/containerd/remotes/docker"
	"github.com/moby/buildkit/cmd/buildkitd/config"
	"github.com/moby/buildkit/session"
	"github.com/moby/buildkit/session/auth"
	"github.com/moby/buildkit/util/tracing"
	"github.com/pkg/errors"
)

func fillInsecureOpts(host string, c config.RegistryConfig, h *docker.RegistryHost) error {
	tc, err := loadTLSConfig(c)
	if err != nil {
		return err
	}

	if c.PlainHTTP != nil && *c.PlainHTTP {
		h.Scheme = "http"
	} else if c.Insecure != nil && *c.Insecure {
		tc.InsecureSkipVerify = true
	} else if c.PlainHTTP == nil {
		if ok, _ := docker.MatchLocalhost(host); ok {
			h.Scheme = "http"
		}
	}

	transport := newDefaultTransport()
	transport.TLSClientConfig = tc

	h.Client = &http.Client{
		Transport: tracing.NewTransport(transport),
	}
	return nil
}

func loadTLSConfig(c config.RegistryConfig) (*tls.Config, error) {
	for _, d := range c.TLSConfigDir {
		fs, err := ioutil.ReadDir(d)
		if err != nil && !errors.Is(err, os.ErrNotExist) && !errors.Is(err, os.ErrPermission) {
			return nil, errors.WithStack(err)
		}
		for _, f := range fs {
			if strings.HasSuffix(f.Name(), ".crt") {
				c.RootCAs = append(c.RootCAs, filepath.Join(d, f.Name()))
			}
			if strings.HasSuffix(f.Name(), ".cert") {
				c.KeyPairs = append(c.KeyPairs, config.TLSKeyPair{
					Certificate: filepath.Join(d, f.Name()),
					Key:         filepath.Join(d, strings.TrimSuffix(f.Name(), ".cert")+".key"),
				})
			}
		}
	}

	tc := &tls.Config{}
	if len(c.RootCAs) > 0 {
		systemPool, err := x509.SystemCertPool()
		if err != nil {
			if runtime.GOOS == "windows" {
				systemPool = x509.NewCertPool()
			} else {
				return nil, errors.Wrapf(err, "unable to get system cert pool")
			}
		}
		tc.RootCAs = systemPool
	}

	for _, p := range c.RootCAs {
		dt, err := ioutil.ReadFile(p)
		if err != nil {
			return nil, errors.Wrapf(err, "failed to read %s", p)
		}
		tc.RootCAs.AppendCertsFromPEM(dt)
	}

	for _, kp := range c.KeyPairs {
		cert, err := tls.LoadX509KeyPair(kp.Certificate, kp.Key)
		if err != nil {
			return nil, errors.Wrapf(err, "failed to load keypair for %s", kp.Certificate)
		}
		tc.Certificates = append(tc.Certificates, cert)
	}
	return tc, nil
}

func NewRegistryConfig(m map[string]config.RegistryConfig) docker.RegistryHosts {
	return docker.Registries(
		func(host string) ([]docker.RegistryHost, error) {
			c, ok := m[host]
			if !ok {
				return nil, nil
			}

			var out []docker.RegistryHost

			for _, mirror := range c.Mirrors {
				h := docker.RegistryHost{
					Scheme:       "https",
					Client:       newDefaultClient(),
					Host:         mirror,
					Path:         "/v2",
					Capabilities: docker.HostCapabilityPull | docker.HostCapabilityResolve,
				}

				if err := fillInsecureOpts(mirror, m[mirror], &h); err != nil {
					return nil, err
				}

				out = append(out, h)
			}

			if host == "docker.io" {
				host = "registry-1.docker.io"
			}

			h := docker.RegistryHost{
				Scheme:       "https",
				Client:       newDefaultClient(),
				Host:         host,
				Path:         "/v2",
				Capabilities: docker.HostCapabilityPush | docker.HostCapabilityPull | docker.HostCapabilityResolve,
			}

			if err := fillInsecureOpts(host, c, &h); err != nil {
				return nil, err
			}

			out = append(out, h)
			return out, nil
		},
		docker.ConfigureDefaultRegistries(
			docker.WithClient(newDefaultClient()),
			docker.WithPlainHTTP(docker.MatchLocalhost),
		),
	)
}

type SessionAuthenticator struct {
	sm      *session.Manager
	groups  []session.Group
	mu      sync.RWMutex
	cache   map[string]credentials
	cacheMu sync.RWMutex
}

type credentials struct {
	user    string
	secret  string
	created time.Time
}

func NewSessionAuthenticator(sm *session.Manager, g session.Group) *SessionAuthenticator {
	return &SessionAuthenticator{sm: sm, groups: []session.Group{g}, cache: map[string]credentials{}}
}

func (a *SessionAuthenticator) credentials(h string) (string, string, error) {
	const credentialsTimeout = time.Minute

	a.cacheMu.RLock()
	c, ok := a.cache[h]
	if ok && time.Since(c.created) < credentialsTimeout {
		a.cacheMu.RUnlock()
		return c.user, c.secret, nil
	}
	a.cacheMu.RUnlock()

	a.mu.RLock()
	defer a.mu.RUnlock()

	var err error
	for i := len(a.groups) - 1; i >= 0; i-- {
		var user, secret string
		user, secret, err = auth.CredentialsFunc(a.sm, a.groups[i])(h)
		if err != nil {
			continue
		}
		a.cacheMu.Lock()
		a.cache[h] = credentials{user: user, secret: secret, created: time.Now()}
		a.cacheMu.Unlock()
		return user, secret, nil
	}
	return "", "", err
}

func (a *SessionAuthenticator) AddSession(g session.Group) {
	a.mu.Lock()
	a.groups = append(a.groups, g)
	a.mu.Unlock()
}

func New(hosts docker.RegistryHosts, auth *SessionAuthenticator) remotes.Resolver {
	return docker.NewResolver(docker.ResolverOptions{
		Hosts: hostsWithCredentials(hosts, auth),
	})
}

func hostsWithCredentials(hosts docker.RegistryHosts, auth *SessionAuthenticator) docker.RegistryHosts {
	if hosts == nil {
		return nil
	}
	return func(domain string) ([]docker.RegistryHost, error) {
		res, err := hosts(domain)
		if err != nil {
			return nil, err
		}
		if len(res) == 0 {
			return nil, nil
		}

		a := docker.NewDockerAuthorizer(
			docker.WithAuthClient(res[0].Client),
			docker.WithAuthCreds(auth.credentials),
		)
		for i := range res {
			res[i].Authorizer = a
		}
		return res, nil
	}
}

func newDefaultClient() *http.Client {
	return &http.Client{
		Transport: newDefaultTransport(),
	}
}

// newDefaultTransport is for pull or push client
//
// NOTE: For push, there must disable http2 for https because the flow control
// will limit data transfer. The net/http package doesn't provide http2 tunable
// settings which limits push performance.
//
// REF: https://github.com/golang/go/issues/14077
func newDefaultTransport() *http.Transport {
	return &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).DialContext,
		MaxIdleConns:          10,
		IdleConnTimeout:       30 * time.Second,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 5 * time.Second,
		DisableKeepAlives:     true,
		TLSNextProto:          make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
	}
}
<|endoftext|>


<commit_before>package testutil

import (
	"encoding/json"
	"fmt"
	"github.com/APTrust/exchange/constants"
	"github.com/APTrust/exchange/models"
	"github.com/APTrust/exchange/util/fileutil"
	"github.com/icrowley/fake"
	"github.com/nu7hatch/gouuid"
	"math"
	"math/rand"
	"strings"
	"time"
)

// Bloomsday
var TEST_TIMESTAMP time.Time = time.Date(2016, 6, 16, 10, 24, 16, 0, time.UTC)

func MakeChecksum() (*models.Checksum) {
	return &models.Checksum{
		Id: rand.Intn(50000) + 1,
		GenericFileId: rand.Intn(50000) + 1,
		Algorithm: RandomAlgorithm(),
		DateTime: RandomDateTime(),
		Digest: fake.Sentence(),
	}
}

func MakeGenericFile(eventCount, checksumCount int, objIdentifier string) (*models.GenericFile) {
	if objIdentifier == "" {
		objIdentifier = RandomObjectIdentifier()
	}
	objIdParts := strings.Split(objIdentifier, "/")
	inst := objIdParts[0]
	objName := objIdParts[1]
	fileIdentifier := RandomFileIdentifier(objIdentifier)
	_uuid, _ := uuid.NewV4()
	checksums := make([]*models.Checksum, checksumCount)
	events := make([]*models.PremisEvent, eventCount)
	for i := 0; i < checksumCount; i++ {
		checksums[i] = MakeChecksum()
	}
	for i := 0; i < eventCount; i++ {
		events[i] = MakePremisEvent()
	}
	return &models.GenericFile {
		Id: rand.Intn(50000) + 1,
		Identifier: fileIdentifier,
		IntellectualObjectId: rand.Intn(50000) + 1,
		IntellectualObjectIdentifier: objIdentifier,
		FileFormat: RandomFileFormat(),
		URI: fmt.Sprintf("%s/%s.%s/%s", constants.S3UriPrefix, constants.ReceiveTestBucketPrefix, inst, objName),
		Size: int64(rand.Intn(5000000) + 1),
		FileCreated: RandomDateTime(),
		FileModified: RandomDateTime(),
		CreatedAt: RandomDateTime(),
		UpdatedAt: RandomDateTime(),
		Checksums: checksums,
		PremisEvents: events,
		IngestLocalPath: fmt.Sprintf("/mnt/aptrust/data/%s", fileIdentifier),
		IngestMd5: fake.CharactersN(32),
		IngestMd5VerifiedAt: RandomDateTime(),
		IngestSha256: fake.CharactersN(64),
		IngestSha256GeneratedAt: RandomDateTime(),
		IngestUUID: _uuid.String(),
		IngestUUIDGeneratedAt: RandomDateTime(),
		IngestStorageURL: fmt.Sprintf("https://storage.aws/%s", _uuid.String()),
		IngestStoredAt: RandomDateTime(),
		IngestReplicationURL: fmt.Sprintf("https://replication.aws/%s", _uuid.String()),
		IngestReplicatedAt: RandomDateTime(),
		IngestPreviousVersionExists: false,
		IngestNeedsSave: true,
		IngestErrorMessage: "",
	}
}

func MakeInstitution() (*models.Institution) {
	return &models.Institution{
		Id: rand.Intn(50000) + 1,
		Name: fake.Product(),
		BriefName: fake.Word(),
		Identifier: fake.DomainName(),
	}
}

func MakeIntellectualObject(fileCount, eventCount, checksumCount, tagCount int) (*models.IntellectualObject) {
	objIdentifier := RandomObjectIdentifier()
	objIdParts := strings.Split(objIdentifier, "/")
	inst := objIdParts[0]
	objName := objIdParts[1]
	files := make([]*models.GenericFile, fileCount)
	events := make([]*models.PremisEvent, eventCount)
	tags := make([]*models.Tag, tagCount)
	for i := 0; i < fileCount; i++ {
		files[i] = MakeGenericFile(eventCount, checksumCount, objIdentifier)
	}
	for i := 0; i < eventCount; i++ {
		events[i] = MakePremisEvent()
	}
	for i := 0; i < tagCount; i++ {
		tags[i] = MakeTag()
	}
	return &models.IntellectualObject{
		Id: rand.Intn(50000) + 1,
		Identifier: objIdentifier,
		BagName: objName,
		Institution: inst,
		InstitutionId: rand.Intn(50000) + 1,
		Title: fake.Words(),
		Description: fake.Sentence(),
		Access: RandomAccess(),
		AltIdentifier: fake.Word(),
		GenericFiles: files,
		PremisEvents: events,
		CreatedAt: RandomDateTime(),
		UpdatedAt: RandomDateTime(),
		IngestS3Bucket: fmt.Sprintf("%s.%s", constants.ReceiveTestBucketPrefix, inst),
		IngestS3Key: fmt.Sprintf("%s.tar", objName),
		IngestTarFilePath: fmt.Sprintf("/mnt/aptrust/data/%s/%s.tar", inst, objName),
		IngestUntarredPath: fmt.Sprintf("/mnt/aptrust/data/%s/%s/", inst, objName),
		IngestRemoteMd5: fake.Word(),
		IngestLocalMd5: fake.Word(),
		IngestMd5Verified: false,
		IngestMd5Verifiable: false,
		IngestFilesIgnored: make([]string, 0),
		IngestTags: tags,
		IngestErrorMessage: "",
	}
}

func MakePremisEvent() (*models.PremisEvent) {
	_uuid, _ := uuid.NewV4()
	return &models.PremisEvent{
		Id: rand.Intn(50000) + 1,
		Identifier: _uuid.String(),
		EventType: RandomEventType(),
		DateTime: RandomDateTime(),
		Detail: fake.Words(),
		Outcome: fake.Word(),
		OutcomeDetail: fake.Sentence(),
		Object: fake.Words(),
		Agent: fake.MaleFullName(),
		OutcomeInformation: fake.Sentence(),
	}
}

func MakeTag() (*models.Tag) {
	return &models.Tag{
		Label: fake.Word(),
		Value: fake.Sentence(),
	}
}

func MakeWorkItem() (*models.WorkItem) {
	return &models.WorkItem{
		Id: rand.Intn(50000) + 1,
		ObjectIdentifier: RandomObjectIdentifier(),
		GenericFileIdentifier: "",
		Name: fake.Word(),
		Bucket: "aptrust.receiving.virginia.edu",
		ETag: fake.Word(),
		BagDate: RandomDateTime(),
		InstitutionId: rand.Intn(50000) + 1,
		User: fake.EmailAddress(),
		Date: RandomDateTime(),
		Note: fake.Sentence(),
		Action: RandomAction(),
		Stage: RandomStage(),
		Status: RandomStatus(),
		Outcome: fake.Sentence(),
		Retry: true,
		Node: fake.Word(),
		Pid: rand.Intn(50000) + 1,
		NeedsAdminReview: false,
	}
}

func MakeWorkItemState() (*models.WorkItemState) {
	return &models.WorkItemState{
		Id: rand.Intn(50000) + 1,
		WorkItemId: rand.Intn(50000) + 1,
		Action: constants.ActionIngest,
		State: `{"key1":"value1","key2":"value2"}`,
		CreatedAt: RandomDateTime(),
		UpdatedAt: time.Now().UTC(),
	}
}

func MakeWorkSummary() (*models.WorkSummary) {
	return &models.WorkSummary{
		Attempted: true,
		AttemptNumber: 1,
		Errors: make([]string, 0),
		StartedAt: RandomDateTime(),
		FinishedAt: time.Now().UTC(),
		Retry: true,
	}
}

func RandomDateTime() (time.Time) {
	t := time.Now().UTC()
	minutes := rand.Intn(500000) * -1
	return t.Add(time.Duration(minutes) * time.Minute)
}

func RandomAccess() (string) {
	access := []string{"consortia", "institution", "restricted"}
	return RandomFromList(access)
}

func RandomAlgorithm() (string) {
	algs := []string{"md5", "sha256", "sha512"}
	return RandomFromList(algs)
}

func RandomObjectIdentifier() (string) {
	return fmt.Sprintf("%s/%s", fake.DomainName(), fake.FemalePatronymic())
}

func RandomFileIdentifier(objectIdentifier string) (string) {
	if objectIdentifier == "" {
		objectIdentifier = RandomObjectIdentifier()
	}
	extensions := []string{"jpg", "tiff", "ogg", "txt", "xml", "pdf", "mp3", "mp4"}
	ext := RandomFromList(extensions)
	return fmt.Sprintf("%s/%s/%s.%s", objectIdentifier, fake.FemaleFirstName(), fake.ProductName(), ext)
}

func RandomFileFormat() (string) {
	formats := []string{"text/plain", "application/pdf", "audio/x-aac",
		"application/x-doom", "application/vnd.ms-excel"}
	return RandomFromList(formats)
}

func RandomEventType() (string) {
	return RandomFromList(constants.EventTypes)
}

func RandomAction() (string) {
	return RandomFromList(constants.ActionTypes)
}

func RandomStage() (string) {
	return RandomFromList(constants.StageTypes)
}

func RandomStatus() (string) {
	return RandomFromList(constants.StatusTypes)
}

func RandomFromList(items []string) (string) {
	i := int(math.Mod(float64(rand.Intn(200)), float64(len(items))))
	return items[i]
}

// Loads an IntellectualObject fixture (a JSON file) from
// the testdata directory for testing.
func LoadIntelObjFixture(filename string) (*models.IntellectualObject, error) {
	data, err := fileutil.LoadRelativeFile(filename)
	if err != nil {
		return nil, err
	}
	intelObj := &models.IntellectualObject{}
	err = json.Unmarshal(data, intelObj)
	if err != nil {
		return nil, err
	}
	return intelObj, nil
}
<commit_msg>Set IngestMd5GeneratedAt<commit_after>package testutil

import (
	"encoding/json"
	"fmt"
	"github.com/APTrust/exchange/constants"
	"github.com/APTrust/exchange/models"
	"github.com/APTrust/exchange/util/fileutil"
	"github.com/icrowley/fake"
	"github.com/nu7hatch/gouuid"
	"math"
	"math/rand"
	"strings"
	"time"
)

// Bloomsday
var TEST_TIMESTAMP time.Time = time.Date(2016, 6, 16, 10, 24, 16, 0, time.UTC)

func MakeChecksum() (*models.Checksum) {
	return &models.Checksum{
		Id: rand.Intn(50000) + 1,
		GenericFileId: rand.Intn(50000) + 1,
		Algorithm: RandomAlgorithm(),
		DateTime: RandomDateTime(),
		Digest: fake.Sentence(),
	}
}

func MakeGenericFile(eventCount, checksumCount int, objIdentifier string) (*models.GenericFile) {
	if objIdentifier == "" {
		objIdentifier = RandomObjectIdentifier()
	}
	objIdParts := strings.Split(objIdentifier, "/")
	inst := objIdParts[0]
	objName := objIdParts[1]
	fileIdentifier := RandomFileIdentifier(objIdentifier)
	_uuid, _ := uuid.NewV4()
	checksums := make([]*models.Checksum, checksumCount)
	events := make([]*models.PremisEvent, eventCount)
	for i := 0; i < checksumCount; i++ {
		checksums[i] = MakeChecksum()
	}
	for i := 0; i < eventCount; i++ {
		events[i] = MakePremisEvent()
	}
	return &models.GenericFile {
		Id: rand.Intn(50000) + 1,
		Identifier: fileIdentifier,
		IntellectualObjectId: rand.Intn(50000) + 1,
		IntellectualObjectIdentifier: objIdentifier,
		FileFormat: RandomFileFormat(),
		URI: fmt.Sprintf("%s/%s.%s/%s", constants.S3UriPrefix, constants.ReceiveTestBucketPrefix, inst, objName),
		Size: int64(rand.Intn(5000000) + 1),
		FileCreated: RandomDateTime(),
		FileModified: RandomDateTime(),
		CreatedAt: RandomDateTime(),
		UpdatedAt: RandomDateTime(),
		Checksums: checksums,
		PremisEvents: events,
		IngestLocalPath: fmt.Sprintf("/mnt/aptrust/data/%s", fileIdentifier),
		IngestMd5: fake.CharactersN(32),
		IngestMd5GeneratedAt: RandomDateTime(),
		IngestMd5VerifiedAt: RandomDateTime(),
		IngestSha256: fake.CharactersN(64),
		IngestSha256GeneratedAt: RandomDateTime(),
		IngestUUID: _uuid.String(),
		IngestUUIDGeneratedAt: RandomDateTime(),
		IngestStorageURL: fmt.Sprintf("https://storage.aws/%s", _uuid.String()),
		IngestStoredAt: RandomDateTime(),
		IngestReplicationURL: fmt.Sprintf("https://replication.aws/%s", _uuid.String()),
		IngestReplicatedAt: RandomDateTime(),
		IngestPreviousVersionExists: false,
		IngestNeedsSave: true,
		IngestErrorMessage: "",
	}
}

func MakeInstitution() (*models.Institution) {
	return &models.Institution{
		Id: rand.Intn(50000) + 1,
		Name: fake.Product(),
		BriefName: fake.Word(),
		Identifier: fake.DomainName(),
	}
}

func MakeIntellectualObject(fileCount, eventCount, checksumCount, tagCount int) (*models.IntellectualObject) {
	objIdentifier := RandomObjectIdentifier()
	objIdParts := strings.Split(objIdentifier, "/")
	inst := objIdParts[0]
	objName := objIdParts[1]
	files := make([]*models.GenericFile, fileCount)
	events := make([]*models.PremisEvent, eventCount)
	tags := make([]*models.Tag, tagCount)
	for i := 0; i < fileCount; i++ {
		files[i] = MakeGenericFile(eventCount, checksumCount, objIdentifier)
	}
	for i := 0; i < eventCount; i++ {
		events[i] = MakePremisEvent()
	}
	for i := 0; i < tagCount; i++ {
		tags[i] = MakeTag()
	}
	return &models.IntellectualObject{
		Id: rand.Intn(50000) + 1,
		Identifier: objIdentifier,
		BagName: objName,
		Institution: inst,
		InstitutionId: rand.Intn(50000) + 1,
		Title: fake.Words(),
		Description: fake.Sentence(),
		Access: RandomAccess(),
		AltIdentifier: fake.Word(),
		GenericFiles: files,
		PremisEvents: events,
		CreatedAt: RandomDateTime(),
		UpdatedAt: RandomDateTime(),
		IngestS3Bucket: fmt.Sprintf("%s.%s", constants.ReceiveTestBucketPrefix, inst),
		IngestS3Key: fmt.Sprintf("%s.tar", objName),
		IngestTarFilePath: fmt.Sprintf("/mnt/aptrust/data/%s/%s.tar", inst, objName),
		IngestUntarredPath: fmt.Sprintf("/mnt/aptrust/data/%s/%s/", inst, objName),
		IngestRemoteMd5: fake.Word(),
		IngestLocalMd5: fake.Word(),
		IngestMd5Verified: false,
		IngestMd5Verifiable: false,
		IngestFilesIgnored: make([]string, 0),
		IngestTags: tags,
		IngestErrorMessage: "",
	}
}

func MakePremisEvent() (*models.PremisEvent) {
	_uuid, _ := uuid.NewV4()
	return &models.PremisEvent{
		Id: rand.Intn(50000) + 1,
		Identifier: _uuid.String(),
		EventType: RandomEventType(),
		DateTime: RandomDateTime(),
		Detail: fake.Words(),
		Outcome: fake.Word(),
		OutcomeDetail: fake.Sentence(),
		Object: fake.Words(),
		Agent: fake.MaleFullName(),
		OutcomeInformation: fake.Sentence(),
	}
}

func MakeTag() (*models.Tag) {
	return &models.Tag{
		Label: fake.Word(),
		Value: fake.Sentence(),
	}
}

func MakeWorkItem() (*models.WorkItem) {
	return &models.WorkItem{
		Id: rand.Intn(50000) + 1,
		ObjectIdentifier: RandomObjectIdentifier(),
		GenericFileIdentifier: "",
		Name: fake.Word(),
		Bucket: "aptrust.receiving.virginia.edu",
		ETag: fake.Word(),
		BagDate: RandomDateTime(),
		InstitutionId: rand.Intn(50000) + 1,
		User: fake.EmailAddress(),
		Date: RandomDateTime(),
		Note: fake.Sentence(),
		Action: RandomAction(),
		Stage: RandomStage(),
		Status: RandomStatus(),
		Outcome: fake.Sentence(),
		Retry: true,
		Node: fake.Word(),
		Pid: rand.Intn(50000) + 1,
		NeedsAdminReview: false,
	}
}

func MakeWorkItemState() (*models.WorkItemState) {
	return &models.WorkItemState{
		Id: rand.Intn(50000) + 1,
		WorkItemId: rand.Intn(50000) + 1,
		Action: constants.ActionIngest,
		State: `{"key1":"value1","key2":"value2"}`,
		CreatedAt: RandomDateTime(),
		UpdatedAt: time.Now().UTC(),
	}
}

func MakeWorkSummary() (*models.WorkSummary) {
	return &models.WorkSummary{
		Attempted: true,
		AttemptNumber: 1,
		Errors: make([]string, 0),
		StartedAt: RandomDateTime(),
		FinishedAt: time.Now().UTC(),
		Retry: true,
	}
}

func RandomDateTime() (time.Time) {
	t := time.Now().UTC()
	minutes := rand.Intn(500000) * -1
	return t.Add(time.Duration(minutes) * time.Minute)
}

func RandomAccess() (string) {
	access := []string{"consortia", "institution", "restricted"}
	return RandomFromList(access)
}

func RandomAlgorithm() (string) {
	algs := []string{"md5", "sha256", "sha512"}
	return RandomFromList(algs)
}

func RandomObjectIdentifier() (string) {
	return fmt.Sprintf("%s/%s", fake.DomainName(), fake.FemalePatronymic())
}

func RandomFileIdentifier(objectIdentifier string) (string) {
	if objectIdentifier == "" {
		objectIdentifier = RandomObjectIdentifier()
	}
	extensions := []string{"jpg", "tiff", "ogg", "txt", "xml", "pdf", "mp3", "mp4"}
	ext := RandomFromList(extensions)
	return fmt.Sprintf("%s/%s/%s.%s", objectIdentifier, fake.FemaleFirstName(), fake.ProductName(), ext)
}

func RandomFileFormat() (string) {
	formats := []string{"text/plain", "application/pdf", "audio/x-aac",
		"application/x-doom", "application/vnd.ms-excel"}
	return RandomFromList(formats)
}

func RandomEventType() (string) {
	return RandomFromList(constants.EventTypes)
}

func RandomAction() (string) {
	return RandomFromList(constants.ActionTypes)
}

func RandomStage() (string) {
	return RandomFromList(constants.StageTypes)
}

func RandomStatus() (string) {
	return RandomFromList(constants.StatusTypes)
}

func RandomFromList(items []string) (string) {
	i := int(math.Mod(float64(rand.Intn(200)), float64(len(items))))
	return items[i]
}

// Loads an IntellectualObject fixture (a JSON file) from
// the testdata directory for testing.
func LoadIntelObjFixture(filename string) (*models.IntellectualObject, error) {
	data, err := fileutil.LoadRelativeFile(filename)
	if err != nil {
		return nil, err
	}
	intelObj := &models.IntellectualObject{}
	err = json.Unmarshal(data, intelObj)
	if err != nil {
		return nil, err
	}
	return intelObj, nil
}
<|endoftext|>


<commit_before>package tictactoe

import (
	"bytes"
	"fmt"
)

const (
	dimension          = 3
	standardFieldValue = dimension + 1
)

// Possible return values for CurrentPlayer() and Winner().
const (
	Tie = iota - 1
	Player1
	Player2
)

// Game represents a game of Tic-Tac-Toe. Obtain it by invoking the factory function
// NewGame().
type Game struct {
	board         [][]int
	currentPlayer int
	moveCount     int
	gameOver      bool
	hasWinner     bool
}

func (g Game) String() string {
	var result bytes.Buffer
	for i := 0; i < dimension; i++ {
		for j := 0; j < dimension; j++ {
			result.WriteString(fmt.Sprintf(" %s ", mapValue(g.board[i][j])))
			if j < dimension-1 {
				result.WriteString("|")
			}
		}
		result.WriteString("\n")
		if i < dimension-1 {
			for j := 0; j < dimension; j++ {
				result.WriteString("---")
				if j < dimension-1 {
					result.WriteString("+")
				}
			}
			result.WriteString("\n")
		}
	}
	return result.String()
}

// NewGame is a factory function for a new game of Tic-Tac-Toe.
func NewGame() *Game {
	b := make([][]int, dimension)
	for i := 0; i < dimension; i++ {
		b[i] = make([]int, dimension)
		for j := 0; j < dimension; j++ {
			b[i][j] = standardFieldValue
		}
	}
	return &Game{board: b}
}

// CurrentPlayer returns Player1 or Player2, depending on who has to play next.
func (g Game) CurrentPlayer() int {
	return g.currentPlayer
}

// Winner returns Player 1 or Player 2 depending on who has won or Tie if there
// is no winner (yet).
func (g Game) Winner() int {
	if !g.hasWinner {
		return Tie
	}
	return g.currentPlayer
}

// Over returns true if the game is finished and false otherwise.
func (g Game) Over() bool {
	return g.gameOver
}

// Play takes x and y coordinates (each between 0 and dimension-1 (which is 2)) and marks the field for the
// current player. If the coordinates are out of bounds or the field is already
// marked it will return an error.
func (g *Game) Play(x, y int) error {
	switch {
	case g.gameOver:
		return fmt.Errorf("Game is already over")
	case x < 0 || x > dimension-1 || y < 0 || y > dimension-1:
		return fmt.Errorf("Invalid coordinates")
	case g.board[y][x] != standardFieldValue:
		return fmt.Errorf("Field already marked")
	}

	g.board[y][x] = g.currentPlayer
	g.moveCount++

	g.checkStatus(x, y)
	if !g.gameOver {
		g.currentPlayer = (g.currentPlayer + 1) % 2
	}
	return nil
}

func (g *Game) checkStatus(x, y int) {
	switch {
	case g.moveCount < dimension+2:
		return
	case g.moveCount == dimension*dimension:
		g.gameOver = true
	}

	winCase := dimension * g.currentPlayer
	var row, col, dia, rdia int
	for i := 0; i < dimension; i++ {
		row += g.board[y][i]
		col += g.board[i][x]
		dia += g.board[i][i]
		rdia += g.board[i][dimension-(i+1)]
	}

	if checkFor(winCase, row, col, dia, rdia) {
		g.gameOver = true
		g.hasWinner = true
	}
}

// FieldValue returns the token of the user occupying the field or empty string
// if it is empty.
func (g Game) FieldValue(x, y int) string {
	return mapValue(g.board[y][x])
}

/* Helper functions */

func mapValue(x int) string {
	switch x {
	case 0:
		return "X"
	case 1:
		return "O"
	default:
		return " "
	}
}

func checkFor(value int, items ...int) bool {
	for _, item := range items {
		if value == item {
			return true
		}
	}
	return false
}
<commit_msg>introduce player type<commit_after>package tictactoe

import (
	"bytes"
	"fmt"
)

const (
	dimension          = 3
	standardFieldValue = dimension + 1
)

// Player is the type returned by CurrentPlayer() and Winner(). Its value is either
// Player1, Player2 or Tie.
type Player int

// Possible values of the Player type.
const (
	Tie = iota - 1
	Player1
	Player2
)

// Game represents a game of Tic-Tac-Toe. Obtain it by invoking the factory function
// NewGame().
type Game struct {
	board         [][]int
	currentPlayer int
	moveCount     int
	gameOver      bool
	hasWinner     bool
}

func (g Game) String() string {
	var result bytes.Buffer
	for i := 0; i < dimension; i++ {
		for j := 0; j < dimension; j++ {
			result.WriteString(fmt.Sprintf(" %s ", mapValue(g.board[i][j])))
			if j < dimension-1 {
				result.WriteString("|")
			}
		}
		result.WriteString("\n")
		if i < dimension-1 {
			for j := 0; j < dimension; j++ {
				result.WriteString("---")
				if j < dimension-1 {
					result.WriteString("+")
				}
			}
			result.WriteString("\n")
		}
	}
	return result.String()
}

// NewGame is a factory function for a new game of Tic-Tac-Toe.
func NewGame() *Game {
	b := make([][]int, dimension)
	for i := 0; i < dimension; i++ {
		b[i] = make([]int, dimension)
		for j := 0; j < dimension; j++ {
			b[i][j] = standardFieldValue
		}
	}
	return &Game{board: b}
}

// CurrentPlayer returns Player1 or Player2, depending on who has to play next.
func (g Game) CurrentPlayer() Player {
	return Player(g.currentPlayer)
}

// Winner returns Player 1 or Player 2 depending on who has won or Tie if there
// is no winner (yet).
func (g Game) Winner() Player {
	if !g.hasWinner {
		return Tie
	}
	return Player(g.currentPlayer)
}

// Over returns true if the game is finished and false otherwise.
func (g Game) Over() bool {
	return g.gameOver
}

// Play takes x and y coordinates (each between 0 and dimension-1 (which is 2)) and marks the field for the
// current player. If the coordinates are out of bounds or the field is already
// marked it will return an error.
func (g *Game) Play(x, y int) error {
	switch {
	case g.gameOver:
		return fmt.Errorf("Game is already over")
	case x < 0 || x > dimension-1 || y < 0 || y > dimension-1:
		return fmt.Errorf("Invalid coordinates")
	case g.board[y][x] != standardFieldValue:
		return fmt.Errorf("Field already marked")
	}

	g.board[y][x] = g.currentPlayer
	g.moveCount++

	g.checkStatus(x, y)
	if !g.gameOver {
		g.currentPlayer = (g.currentPlayer + 1) % 2
	}
	return nil
}

func (g *Game) checkStatus(x, y int) {
	switch {
	case g.moveCount < dimension+2:
		return
	case g.moveCount == dimension*dimension:
		g.gameOver = true
	}

	winCase := dimension * g.currentPlayer
	var row, col, dia, rdia int
	for i := 0; i < dimension; i++ {
		row += g.board[y][i]
		col += g.board[i][x]
		dia += g.board[i][i]
		rdia += g.board[i][dimension-(i+1)]
	}

	if checkFor(winCase, row, col, dia, rdia) {
		g.gameOver = true
		g.hasWinner = true
	}
}

// FieldValue returns the token of the user occupying the field or empty string
// if it is empty.
func (g Game) FieldValue(x, y int) string {
	return mapValue(g.board[y][x])
}

/* Helper functions */

func mapValue(x int) string {
	switch x {
	case 0:
		return "X"
	case 1:
		return "O"
	default:
		return " "
	}
}

func checkFor(value int, items ...int) bool {
	for _, item := range items {
		if value == item {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vector

// This file contains a floating point math implementation of the vector
// graphics rasterizer.

import (
	"math"
)

func floatingMax(x, y float32) float32 {
	if x > y {
		return x
	}
	return y
}

func floatingMin(x, y float32) float32 {
	if x < y {
		return x
	}
	return y
}

func floatingFloor(x float32) int32 { return int32(math.Floor(float64(x))) }
func floatingCeil(x float32) int32  { return int32(math.Ceil(float64(x))) }

func (z *Rasterizer) floatingLineTo(bx, by float32) {
	ax, ay := z.penX, z.penY
	z.penX, z.penY = bx, by
	dir := float32(1)
	if ay > by {
		dir, ax, ay, bx, by = -1, bx, by, ax, ay
	}
	// Horizontal line segments yield no change in coverage. Almost horizontal
	// segments would yield some change, in ideal math, but the computation
	// further below, involving 1 / (by - ay), is unstable in floating point
	// math, so we treat the segment as if it was perfectly horizontal.
	if by-ay <= 0.000001 {
		return
	}
	dxdy := (bx - ax) / (by - ay)

	x := ax
	y := floatingFloor(ay)
	yMax := floatingCeil(by)
	if yMax > int32(z.size.Y) {
		yMax = int32(z.size.Y)
	}
	width := int32(z.size.X)

	for ; y < yMax; y++ {
		dy := floatingMin(float32(y+1), by) - floatingMax(float32(y), ay)
		xNext := x + dy*dxdy
		if y < 0 {
			x = xNext
			continue
		}
		buf := z.bufF32[y*width:]
		d := dy * dir
		x0, x1 := x, xNext
		if x > xNext {
			x0, x1 = x1, x0
		}
		x0i := floatingFloor(x0)
		x0Floor := float32(x0i)
		x1i := floatingCeil(x1)
		x1Ceil := float32(x1i)

		if x1i <= x0i+1 {
			xmf := 0.5*(x+xNext) - x0Floor
			if i := clamp(x0i+0, width); i < uint(len(buf)) {
				buf[i] += d - d*xmf
			}
			if i := clamp(x0i+1, width); i < uint(len(buf)) {
				buf[i] += d * xmf
			}
		} else {
			s := 1 / (x1 - x0)
			x0f := x0 - x0Floor
			oneMinusX0f := 1 - x0f
			a0 := 0.5 * s * oneMinusX0f * oneMinusX0f
			x1f := x1 - x1Ceil + 1
			am := 0.5 * s * x1f * x1f

			if i := clamp(x0i, width); i < uint(len(buf)) {
				buf[i] += d * a0
			}

			if x1i == x0i+2 {
				if i := clamp(x0i+1, width); i < uint(len(buf)) {
					buf[i] += d * (1 - a0 - am)
				}
			} else {
				a1 := s * (1.5 - x0f)
				if i := clamp(x0i+1, width); i < uint(len(buf)) {
					buf[i] += d * (a1 - a0)
				}
				dTimesS := d * s
				for xi := x0i + 2; xi < x1i-1; xi++ {
					if i := clamp(xi, width); i < uint(len(buf)) {
						buf[i] += dTimesS
					}
				}
				a2 := a1 + s*float32(x1i-x0i-3)
				if i := clamp(x1i-1, width); i < uint(len(buf)) {
					buf[i] += d * (1 - a2 - am)
				}
			}

			if i := clamp(x1i, width); i < uint(len(buf)) {
				buf[i] += d * am
			}
		}

		x = xNext
	}
}

const (
	// almost256 scales a floating point value in the range [0, 1] to a uint8
	// value in the range [0x00, 0xff].
	//
	// 255 is too small. Floating point math accumulates rounding errors, so a
	// fully covered src value that would in ideal math be float32(1) might be
	// float32(1-ε), and uint8(255 * (1-ε)) would be 0xfe instead of 0xff. The
	// uint8 conversion rounds to zero, not to nearest.
	//
	// 256 is too big. If we multiplied by 256, below, then a fully covered src
	// value of float32(1) would translate to uint8(256 * 1), which can be 0x00
	// instead of the maximal value 0xff.
	//
	// math.Float32bits(almost256) is 0x437fffff.
	almost256 = 255.99998

	// almost65536 scales a floating point value in the range [0, 1] to a
	// uint16 value in the range [0x0000, 0xffff].
	//
	// math.Float32bits(almost65536) is 0x477fffff.
	almost65536 = almost256 * 256
)

func floatingAccumulateOpOver(dst []uint8, src []float32) {
	// Sanity check that len(dst) >= len(src).
	if len(dst) < len(src) {
		return
	}

	acc := float32(0)
	for i, v := range src {
		acc += v
		a := acc
		if a < 0 {
			a = -a
		}
		if a > 1 {
			a = 1
		}
		// This algorithm comes from the standard library's image/draw package.
		dstA := uint32(dst[i]) * 0x101
		maskA := uint32(almost65536 * a)
		outA := dstA*(0xffff-maskA)/0xffff + maskA
		dst[i] = uint8(outA >> 8)
	}
}

func floatingAccumulateOpSrc(dst []uint8, src []float32) {
	// Sanity check that len(dst) >= len(src).
	if len(dst) < len(src) {
		return
	}

	acc := float32(0)
	for i, v := range src {
		acc += v
		a := acc
		if a < 0 {
			a = -a
		}
		if a > 1 {
			a = 1
		}
		dst[i] = uint8(almost256 * a)
	}
}

func floatingAccumulateMask(dst []uint32, src []float32) {
	// Sanity check that len(dst) >= len(src).
	if len(dst) < len(src) {
		return
	}

	acc := float32(0)
	for i, v := range src {
		acc += v
		a := acc
		if a < 0 {
			a = -a
		}
		if a > 1 {
			a = 1
		}
		dst[i] = uint32(almost65536 * a)
	}
}
<commit_msg>vector: prevent fused multiply-add being used in floatingLineTo<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vector

// This file contains a floating point math implementation of the vector
// graphics rasterizer.

import (
	"math"
)

func floatingMax(x, y float32) float32 {
	if x > y {
		return x
	}
	return y
}

func floatingMin(x, y float32) float32 {
	if x < y {
		return x
	}
	return y
}

func floatingFloor(x float32) int32 { return int32(math.Floor(float64(x))) }
func floatingCeil(x float32) int32  { return int32(math.Ceil(float64(x))) }

func (z *Rasterizer) floatingLineTo(bx, by float32) {
	ax, ay := z.penX, z.penY
	z.penX, z.penY = bx, by
	dir := float32(1)
	if ay > by {
		dir, ax, ay, bx, by = -1, bx, by, ax, ay
	}
	// Horizontal line segments yield no change in coverage. Almost horizontal
	// segments would yield some change, in ideal math, but the computation
	// further below, involving 1 / (by - ay), is unstable in floating point
	// math, so we treat the segment as if it was perfectly horizontal.
	if by-ay <= 0.000001 {
		return
	}
	dxdy := (bx - ax) / (by - ay)

	x := ax
	y := floatingFloor(ay)
	yMax := floatingCeil(by)
	if yMax > int32(z.size.Y) {
		yMax = int32(z.size.Y)
	}
	width := int32(z.size.X)

	for ; y < yMax; y++ {
		dy := floatingMin(float32(y+1), by) - floatingMax(float32(y), ay)

		// The "float32" in expressions like "float32(foo*bar)" here and below
		// look redundant, since foo and bar already have type float32, but are
		// explicit in order to disable the compiler's Fused Multiply Add (FMA)
		// instruction selection, which can improve performance but can result
		// in different rounding errors in floating point computations.
		//
		// This package aims to have bit-exact identical results across all
		// GOARCHes, and across pure Go code and assembly, so it disables FMA.
		//
		// See the discussion at
		// https://groups.google.com/d/topic/golang-dev/Sti0bl2xUXQ/discussion
		xNext := x + float32(dy*dxdy)
		if y < 0 {
			x = xNext
			continue
		}
		buf := z.bufF32[y*width:]
		d := float32(dy * dir)
		x0, x1 := x, xNext
		if x > xNext {
			x0, x1 = x1, x0
		}
		x0i := floatingFloor(x0)
		x0Floor := float32(x0i)
		x1i := floatingCeil(x1)
		x1Ceil := float32(x1i)

		if x1i <= x0i+1 {
			xmf := float32(0.5*(x+xNext)) - x0Floor
			if i := clamp(x0i+0, width); i < uint(len(buf)) {
				buf[i] += d - float32(d*xmf)
			}
			if i := clamp(x0i+1, width); i < uint(len(buf)) {
				buf[i] += float32(d * xmf)
			}
		} else {
			s := 1 / (x1 - x0)
			x0f := x0 - x0Floor
			oneMinusX0f := 1 - x0f
			a0 := float32(0.5 * s * oneMinusX0f * oneMinusX0f)
			x1f := x1 - x1Ceil + 1
			am := float32(0.5 * s * x1f * x1f)

			if i := clamp(x0i, width); i < uint(len(buf)) {
				buf[i] += float32(d * a0)
			}

			if x1i == x0i+2 {
				if i := clamp(x0i+1, width); i < uint(len(buf)) {
					buf[i] += float32(d * (1 - a0 - am))
				}
			} else {
				a1 := float32(s * (1.5 - x0f))
				if i := clamp(x0i+1, width); i < uint(len(buf)) {
					buf[i] += float32(d * (a1 - a0))
				}
				dTimesS := float32(d * s)
				for xi := x0i + 2; xi < x1i-1; xi++ {
					if i := clamp(xi, width); i < uint(len(buf)) {
						buf[i] += dTimesS
					}
				}
				a2 := a1 + float32(s*float32(x1i-x0i-3))
				if i := clamp(x1i-1, width); i < uint(len(buf)) {
					buf[i] += float32(d * (1 - a2 - am))
				}
			}

			if i := clamp(x1i, width); i < uint(len(buf)) {
				buf[i] += float32(d * am)
			}
		}

		x = xNext
	}
}

const (
	// almost256 scales a floating point value in the range [0, 1] to a uint8
	// value in the range [0x00, 0xff].
	//
	// 255 is too small. Floating point math accumulates rounding errors, so a
	// fully covered src value that would in ideal math be float32(1) might be
	// float32(1-ε), and uint8(255 * (1-ε)) would be 0xfe instead of 0xff. The
	// uint8 conversion rounds to zero, not to nearest.
	//
	// 256 is too big. If we multiplied by 256, below, then a fully covered src
	// value of float32(1) would translate to uint8(256 * 1), which can be 0x00
	// instead of the maximal value 0xff.
	//
	// math.Float32bits(almost256) is 0x437fffff.
	almost256 = 255.99998

	// almost65536 scales a floating point value in the range [0, 1] to a
	// uint16 value in the range [0x0000, 0xffff].
	//
	// math.Float32bits(almost65536) is 0x477fffff.
	almost65536 = almost256 * 256
)

func floatingAccumulateOpOver(dst []uint8, src []float32) {
	// Sanity check that len(dst) >= len(src).
	if len(dst) < len(src) {
		return
	}

	acc := float32(0)
	for i, v := range src {
		acc += v
		a := acc
		if a < 0 {
			a = -a
		}
		if a > 1 {
			a = 1
		}
		// This algorithm comes from the standard library's image/draw package.
		dstA := uint32(dst[i]) * 0x101
		maskA := uint32(almost65536 * a)
		outA := dstA*(0xffff-maskA)/0xffff + maskA
		dst[i] = uint8(outA >> 8)
	}
}

func floatingAccumulateOpSrc(dst []uint8, src []float32) {
	// Sanity check that len(dst) >= len(src).
	if len(dst) < len(src) {
		return
	}

	acc := float32(0)
	for i, v := range src {
		acc += v
		a := acc
		if a < 0 {
			a = -a
		}
		if a > 1 {
			a = 1
		}
		dst[i] = uint8(almost256 * a)
	}
}

func floatingAccumulateMask(dst []uint32, src []float32) {
	// Sanity check that len(dst) >= len(src).
	if len(dst) < len(src) {
		return
	}

	acc := float32(0)
	for i, v := range src {
		acc += v
		a := acc
		if a < 0 {
			a = -a
		}
		if a > 1 {
			a = 1
		}
		dst[i] = uint32(almost65536 * a)
	}
}
<|endoftext|>