Skip to content

Commit d356cac

Browse files
Implement io.StringWriter on some more types (#2023)
In theory this can optimize some code paths where a string first needs to be converted to a []byte to use the normal Write method. By implementing WriteString this extra copy isn't needed. Internall we don't do the copy and just use s2b instead.
1 parent 641dd96 commit d356cac

File tree

6 files changed

+52
-0
lines changed

6 files changed

+52
-0
lines changed

compress.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,11 @@ func (w *byteSliceWriter) Write(p []byte) (int, error) {
351351
return len(p), nil
352352
}
353353

354+
func (w *byteSliceWriter) WriteString(s string) (int, error) {
355+
w.b = append(w.b, s...)
356+
return len(s), nil
357+
}
358+
354359
type byteSliceReader struct {
355360
b []byte
356361
}

fasthttputil/pipeconns.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ func (c *pipeConn) Write(p []byte) (int, error) {
142142
return len(p), nil
143143
}
144144

145+
func (c *pipeConn) WriteString(s string) (int, error) {
146+
return c.Write(s2b(s))
147+
}
148+
145149
func (c *pipeConn) Read(p []byte) (int, error) {
146150
mayBlock := true
147151
nn := 0

fasthttputil/s2b.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package fasthttputil
2+
3+
import "unsafe"
4+
5+
// s2b converts string to a byte slice without memory allocation.
6+
func s2b(s string) []byte {
7+
return unsafe.Slice(unsafe.StringData(s), len(s))
8+
}

http.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,11 @@ func (w *responseBodyWriter) Write(p []byte) (int, error) {
378378
return len(p), nil
379379
}
380380

381+
func (w *responseBodyWriter) WriteString(s string) (int, error) {
382+
w.r.AppendBodyString(s)
383+
return len(s), nil
384+
}
385+
381386
type requestBodyWriter struct {
382387
r *Request
383388
}
@@ -387,6 +392,11 @@ func (w *requestBodyWriter) Write(p []byte) (int, error) {
387392
return len(p), nil
388393
}
389394

395+
func (w *requestBodyWriter) WriteString(s string) (int, error) {
396+
w.r.AppendBodyString(s)
397+
return len(s), nil
398+
}
399+
390400
func (resp *Response) ParseNetConn(conn net.Conn) {
391401
resp.raddr = conn.RemoteAddr()
392402
resp.laddr = conn.LocalAddr()
@@ -1544,6 +1554,12 @@ func (w *statsWriter) Write(p []byte) (int, error) {
15441554
return n, err
15451555
}
15461556

1557+
func (w *statsWriter) WriteString(s string) (int, error) {
1558+
n, err := w.w.Write(s2b(s))
1559+
w.bytesWritten += int64(n)
1560+
return n, err
1561+
}
1562+
15471563
func acquireStatsWriter(w io.Writer) *statsWriter {
15481564
v := statsWriterPool.Get()
15491565
if v == nil {
@@ -1969,6 +1985,10 @@ func (w *flushWriter) Write(p []byte) (int, error) {
19691985
return n, nil
19701986
}
19711987

1988+
func (w *flushWriter) WriteString(s string) (int, error) {
1989+
return w.Write(s2b(s))
1990+
}
1991+
19721992
// Write writes response to w.
19731993
//
19741994
// Write doesn't flush response to w for performance reasons.

stackless/s2b.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package stackless
2+
3+
import "unsafe"
4+
5+
// s2b converts string to a byte slice without memory allocation.
6+
func s2b(s string) []byte {
7+
return unsafe.Slice(unsafe.StringData(s), len(s))
8+
}

stackless/writer.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ func (w *writer) Write(p []byte) (int, error) {
6767
return w.n, err
6868
}
6969

70+
func (w *writer) WriteString(s string) (int, error) {
71+
w.p = s2b(s)
72+
err := w.do(opWrite)
73+
w.p = nil
74+
return w.n, err
75+
}
76+
7077
func (w *writer) Flush() error {
7178
return w.do(opFlush)
7279
}

0 commit comments

Comments
 (0)