1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// +build go1.3
6
7package v1
8
9// Allocation pools for Buffers.
10
11import "sync"
12
13var pools [14]sync.Pool
14var pool64 *sync.Pool
15
16func init() {
17	var i uint
18	// TODO(pquerna): add science here around actual pool sizes.
19	for i = 6; i < 20; i++ {
20		n := 1 << i
21		pools[poolNum(n)].New = func() interface{} { return make([]byte, 0, n) }
22	}
23	pool64 = &pools[0]
24}
25
26// This returns the pool number that will give a buffer of
27// at least 'i' bytes.
28func poolNum(i int) int {
29	// TODO(pquerna): convert to log2 w/ bsr asm instruction:
30	// 	<https://groups.google.com/forum/#!topic/golang-nuts/uAb5J1_y7ns>
31	if i <= 64 {
32		return 0
33	} else if i <= 128 {
34		return 1
35	} else if i <= 256 {
36		return 2
37	} else if i <= 512 {
38		return 3
39	} else if i <= 1024 {
40		return 4
41	} else if i <= 2048 {
42		return 5
43	} else if i <= 4096 {
44		return 6
45	} else if i <= 8192 {
46		return 7
47	} else if i <= 16384 {
48		return 8
49	} else if i <= 32768 {
50		return 9
51	} else if i <= 65536 {
52		return 10
53	} else if i <= 131072 {
54		return 11
55	} else if i <= 262144 {
56		return 12
57	} else if i <= 524288 {
58		return 13
59	} else {
60		return -1
61	}
62}
63
64// Send a buffer to the Pool to reuse for other instances.
65// You may no longer utilize the content of the buffer, since it may be used
66// by other goroutines.
67func Pool(b []byte) {
68	if b == nil {
69		return
70	}
71	c := cap(b)
72
73	// Our smallest buffer is 64 bytes, so we discard smaller buffers.
74	if c < 64 {
75		return
76	}
77
78	// We need to put the incoming buffer into the NEXT buffer,
79	// since a buffer guarantees AT LEAST the number of bytes available
80	// that is the top of this buffer.
81	// That is the reason for dividing the cap by 2, so it gets into the NEXT bucket.
82	// We add 2 to avoid rounding down if size is exactly power of 2.
83	pn := poolNum((c + 2) >> 1)
84	if pn != -1 {
85		pools[pn].Put(b[0:0])
86	}
87	// if we didn't have a slot for this []byte, we just drop it and let the GC
88	// take care of it.
89}
90
91// makeSlice allocates a slice of size n -- it will attempt to use a pool'ed
92// instance whenever possible.
93func makeSlice(n int) []byte {
94	if n <= 64 {
95		return pool64.Get().([]byte)[0:n]
96	}
97
98	pn := poolNum(n)
99
100	if pn != -1 {
101		return pools[pn].Get().([]byte)[0:n]
102	} else {
103		return make([]byte, n)
104	}
105}
106