<commit_before>// Copyright (c) 2016 <NAME>. All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package tiny

import (
	"bytes"
	"net/http"
	"sync"
)

type Tree struct {
	handlers       []Handler
	names          []string
	methods, nodes map[string]*Node
	pool           sync.Pool
}

func (t *Tree) naming(name string, n *Node) {
	if len(name) > 0 {
		if t.nodes == nil {
			t.nodes = map[string]*Node{name: n}
		} else if _, ok := t.nodes[name]; ok {
			panic("duplicate route name: " + name)
		} else {
			t.nodes[name] = n
		}
	}
}

func (t *Tree) getParams() []string {
	if t.pool.New == nil {
		t.pool.New = func() interface{} {
			return make([]string, len(t.names))
		}
	}
	return t.pool.Get().([]string)
}

func (t *Tree) putParams(params []string) {
	t.pool.Put(params[:len(t.names)])
}

func (t *Tree) match(method, path string) (n *Node, params []string) {
	params = t.getParams()
	f := func(s string) (ok bool) {
		n, ok = t.methods[s]
		if ok {
			n, ok = n.match(path, params[:0])
			if ok && n != nil && n.handlers != nil {
				params = params[:len(n.names)]
				return true
			}
		}
		return false
	}
	if f(method) {
		return
	}
	if method != "" && f("") {
		return
	}
	n, params = nil, params[:0]
	return
}

func (t *Tree) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.RequestURI == "*" {
		if r.ProtoAtLeast(1, 1) {
			w.Header().Set("Connection", "close")
		}
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	n, params := t.match(r.Method, r.URL.Path)
	ctx := &Context{ResponseWriter: w, Request: r, Params: params, tree: t, node: n}
	ctx.call(ctx.index)
	t.putParams(params)
}

func newTree(r *Router) *Tree {
	if r.above != nil {
		panic("subrouter not allowed")
	}
	t := &Tree{
		methods:  make(map[string]*Node, 10),
		handlers: copyHandlers(r.handlers),
	}
	var i int
	handlers := make([]Handler, 0, 10)
	tags := make([]Tag, 0, 10)
Loop:
	for {
		if r.above != nil {
			handlers = append(handlers, r.handlers...)
		}
		for ; i < len(r.routes); i++ {
			rr := r.routes[i]
			handlers = append(handlers, rr.handlers...)
			tags = append(tags, rr.tags...)
			if rr.below != nil {
				r = rr.below
				i = 0
				continue Loop
			}
			n, ok := t.methods[rr.method]
			if !ok {
				n = new(Node)
				t.methods[rr.method] = n
			}
			var names []string
			k := 0
			for _, tag := range tags {<commit_msg>fix copy handlers more than once<commit_after>// Copyright (c) 2016 <NAME>. All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package tiny

import (
	"bytes"
	"net/http"
	"sync"
)

type Tree struct {
	handlers       []Handler
	names          []string
	methods, nodes map[string]*Node
	pool           sync.Pool
}

func (t *Tree) naming(name string, n *Node) {
	if len(name) > 0 {
		if t.nodes == nil {
			t.nodes = map[string]*Node{name: n}
		} else if _, ok := t.nodes[name]; ok {
			panic("duplicate route name: " + name)
		} else {
			t.nodes[name] = n
		}
	}
}

func (t *Tree) getParams() []string {
	if t.pool.New == nil {
		t.pool.New = func() interface{} {
			return make([]string, len(t.names))
		}
	}
	return t.pool.Get().([]string)
}

func (t *Tree) putParams(params []string) {
	t.pool.Put(params[:len(t.names)])
}

func (t *Tree) match(method, path string) (n *Node, params []string) {
	params = t.getParams()
	f := func(s string) (ok bool) {
		n, ok = t.methods[s]
		if ok {
			n, ok = n.match(path, params[:0])
			if ok && n != nil && n.handlers != nil {
				params = params[:len(n.names)]
				return true
			}
		}
		return false
	}
	if f(method) {
		return
	}
	if method != "" && f("") {
		return
	}
	n, params = nil, params[:0]
	return
}

func (t *Tree) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.RequestURI == "*" {
		if r.ProtoAtLeast(1, 1) {
			w.Header().Set("Connection", "close")
		}
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	n, params := t.match(r.Method, r.URL.Path)
	ctx := &Context{ResponseWriter: w, Request: r, Params: params, tree: t, node: n}
	ctx.call(ctx.index)
	t.putParams(params)
}

func newTree(r *Router) *Tree {
	if r.above != nil {
		panic("subrouter not allowed")
	}
	t := &Tree{
		methods:  make(map[string]*Node, 10),
		handlers: copyHandlers(r.handlers),
	}
	var i int
	handlers := make([]Handler, 0, 10)
	tags := make([]Tag, 0, 10)
Loop:
	for {
		if r.above != nil && i == 0 {
			handlers = append(handlers, r.handlers...)
		}
		for ; i < len(r.routes); i++ {
			rr := r.routes[i]
			handlers = append(handlers, rr.handlers...)
			tags = append(tags, rr.tags...)
			if rr.below != nil {
				r = rr.below
				i = 0
				continue Loop
			}
			n, ok := t.methods[rr.method]
			if !ok {
				n = new(Node)
				t.methods[rr.method] = n
			}
			var names []string
			k := 0
			for _, tag := range tags {
{'fraction_non_alphanumeric': 0.17614223692371306, 'fraction_numerical': 0.008062848873268556, 'mean_word_length': 2.8335974643423136, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '385436', 'n_tokens_mistral': 2092, 'n_tokens_neox': 1881, 'n_words': 513}