Skip to content

Commit 1c85d43

Browse files
committedJul 8, 2023
Fix round2
- don't limit it to 32 bits - give it a proper name - don't over-allocate too much
1 parent 064124e commit 1c85d43

File tree

4 files changed

+77
-38
lines changed

4 files changed

+77
-38
lines changed
 

‎http.go

+2-23
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"errors"
99
"fmt"
1010
"io"
11-
"math"
1211
"mime/multipart"
1312
"net"
1413
"os"
@@ -2210,7 +2209,7 @@ func readBodyIdentity(r *bufio.Reader, maxBodySize int, dst []byte) ([]byte, err
22102209
return dst[:offset], ErrBodyTooLarge
22112210
}
22122211
if len(dst) == offset {
2213-
n := round2(2 * offset)
2212+
n := roundUpForSliceCap(2 * offset)
22142213
if maxBodySize > 0 && n > maxBodySize {
22152214
n = maxBodySize + 1
22162215
}
@@ -2229,7 +2228,7 @@ func appendBodyFixedSize(r *bufio.Reader, dst []byte, n int) ([]byte, error) {
22292228
offset := len(dst)
22302229
dstLen := offset + n
22312230
if cap(dst) < dstLen {
2232-
b := make([]byte, round2(dstLen))
2231+
b := make([]byte, roundUpForSliceCap(dstLen))
22332232
copy(b, dst)
22342233
dst = b
22352234
}
@@ -2339,26 +2338,6 @@ func readCrLf(r *bufio.Reader) error {
23392338
return nil
23402339
}
23412340

2342-
func round2(n int) int {
2343-
if n <= 0 {
2344-
return 0
2345-
}
2346-
2347-
x := uint32(n - 1)
2348-
x |= x >> 1
2349-
x |= x >> 2
2350-
x |= x >> 4
2351-
x |= x >> 8
2352-
x |= x >> 16
2353-
2354-
// Make sure we don't return 0 due to overflow, even on 32 bit systems
2355-
if x >= uint32(math.MaxInt32) {
2356-
return math.MaxInt32
2357-
}
2358-
2359-
return int(x + 1)
2360-
}
2361-
23622341
// SetTimeout sets timeout for the request.
23632342
//
23642343
// req.SetTimeout(t); c.Do(&req, &resp) is equivalent to

‎http_test.go

+22-15
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"strings"
1717
"testing"
1818
"time"
19+
"unsafe"
1920

2021
"github.com/valyala/bytebufferpool"
2122
)
@@ -1967,25 +1968,31 @@ func testSetResponseBodyStreamChunked(t *testing.T, body string, trailer map[str
19671968
}
19681969
}
19691970

1970-
func TestRound2(t *testing.T) {
1971+
func TestRound2ForSliceCap(t *testing.T) {
19711972
t.Parallel()
19721973

1973-
testRound2(t, 0, 0)
1974-
testRound2(t, 1, 1)
1975-
testRound2(t, 2, 2)
1976-
testRound2(t, 3, 4)
1977-
testRound2(t, 4, 4)
1978-
testRound2(t, 5, 8)
1979-
testRound2(t, 7, 8)
1980-
testRound2(t, 8, 8)
1981-
testRound2(t, 9, 16)
1982-
testRound2(t, 0x10001, 0x20000)
1983-
testRound2(t, math.MaxInt32-1, math.MaxInt32)
1974+
testRound2ForSliceCap(t, 0, 0)
1975+
testRound2ForSliceCap(t, 1, 1)
1976+
testRound2ForSliceCap(t, 2, 2)
1977+
testRound2ForSliceCap(t, 3, 4)
1978+
testRound2ForSliceCap(t, 4, 4)
1979+
testRound2ForSliceCap(t, 5, 8)
1980+
testRound2ForSliceCap(t, 7, 8)
1981+
testRound2ForSliceCap(t, 8, 8)
1982+
testRound2ForSliceCap(t, 9, 16)
1983+
testRound2ForSliceCap(t, 0x10001, 0x20000)
1984+
1985+
if unsafe.Sizeof(int(0)) == 4 {
1986+
testRound2ForSliceCap(t, math.MaxInt32-1, math.MaxInt32)
1987+
} else {
1988+
testRound2ForSliceCap(t, math.MaxInt32, math.MaxInt32)
1989+
testRound2ForSliceCap(t, math.MaxInt64-1, math.MaxInt64-1)
1990+
}
19841991
}
19851992

1986-
func testRound2(t *testing.T, n, expectedRound2 int) {
1987-
if round2(n) != expectedRound2 {
1988-
t.Fatalf("Unexpected round2(%d)=%d. Expected %d", n, round2(n), expectedRound2)
1993+
func testRound2ForSliceCap(t *testing.T, n, expectedRound2 int) {
1994+
if roundUpForSliceCap(n) != expectedRound2 {
1995+
t.Fatalf("Unexpected round2(%d)=%d. Expected %d", n, roundUpForSliceCap(n), expectedRound2)
19891996
}
19901997
}
19911998

‎round2_32.go

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//go:build !amd64 && !arm64 && !ppc64 && !ppc64le && !s390x
2+
// +build !amd64,!arm64,!ppc64,!ppc64le,!s390x
3+
4+
package fasthttp
5+
6+
func roundUpForSliceCap(n int) int {
7+
if n <= 0 {
8+
return 0
9+
}
10+
11+
// Above 100MB, we don't round up as the overhead is too large.
12+
if n > 100*1024*1024 {
13+
return n
14+
}
15+
16+
x := uint32(n - 1)
17+
x |= x >> 1
18+
x |= x >> 2
19+
x |= x >> 4
20+
x |= x >> 8
21+
x |= x >> 16
22+
23+
// Make sure we don't return 0 due to overflow, even on 32 bit systems
24+
if x >= uint32(math.MaxInt32) {
25+
return math.MaxInt32
26+
}
27+
28+
return int(x + 1)
29+
}

‎round2_64.go

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//go:build amd64 || arm64 || ppc64 || ppc64le || s390x
2+
// +build amd64 arm64 ppc64 ppc64le s390x
3+
4+
package fasthttp
5+
6+
func roundUpForSliceCap(n int) int {
7+
if n <= 0 {
8+
return 0
9+
}
10+
11+
// Above 100MB, we don't round up as the overhead is too large.
12+
if n > 100*1024*1024 {
13+
return n
14+
}
15+
16+
x := uint64(n - 1)
17+
x |= x >> 1
18+
x |= x >> 2
19+
x |= x >> 4
20+
x |= x >> 8
21+
x |= x >> 16
22+
23+
return int(x + 1)
24+
}

0 commit comments

Comments
 (0)
Please sign in to comment.