1
0
mirror of https://github.com/golang/go synced 2024-11-25 03:07:56 -07:00

runtime: append([]byte, string...)

Fixes #2274

R=rsc, gri, dsymonds, bradfitz, lvd
CC=golang-dev
https://golang.org/cl/5149045
This commit is contained in:
Luuk van Dijk 2011-10-12 15:59:23 +02:00
parent a0d335c31d
commit 77fac21e82
7 changed files with 95 additions and 56 deletions

View File

@ -1,5 +1,5 @@
<!-- title The Go Programming Language Specification --> <!-- title The Go Programming Language Specification -->
<!-- subtitle Version of August 31, 2011 --> <!-- subtitle Version of September 29, 2011 -->
<!-- <!--
TODO TODO
@ -4658,6 +4658,10 @@ The values <code>x</code> are passed to a parameter of type <code>...T</code>
where <code>T</code> is the <a href="#Slice_types">element type</a> of where <code>T</code> is the <a href="#Slice_types">element type</a> of
<code>S</code> and the respective <code>S</code> and the respective
<a href="#Passing_arguments_to_..._parameters">parameter passing rules</a> apply. <a href="#Passing_arguments_to_..._parameters">parameter passing rules</a> apply.
As a special case, <code>append</code> also accepts a first argument
assignable to type <code>[]byte</code> with a second argument of
string type followed by <code>...</code>. This form appends the
bytes of the string.
</p> </p>
<pre class="grammar"> <pre class="grammar">
@ -4679,6 +4683,9 @@ s3 := append(s2, s0...) // append a slice s3 == []int{0, 0, 2, 3
var t []interface{} var t []interface{}
t = append(t, 42, 3.1415, "foo") t == []interface{}{42, 3.1415, "foo"} t = append(t, 42, 3.1415, "foo") t == []interface{}{42, 3.1415, "foo"}
var b []byte
b = append(b, "bar"...) // append string contents b == []byte{'b', 'a', 'r' }
</pre> </pre>
<p> <p>

View File

@ -25,6 +25,7 @@ char *runtimeimport =
"func @\"\".concatstring ()\n" "func @\"\".concatstring ()\n"
"func @\"\".append ()\n" "func @\"\".append ()\n"
"func @\"\".appendslice (typ *uint8, x any, y []any) any\n" "func @\"\".appendslice (typ *uint8, x any, y []any) any\n"
"func @\"\".appendstr (typ *uint8, x []uint8, y string) []uint8\n"
"func @\"\".cmpstring (? string, ? string) int\n" "func @\"\".cmpstring (? string, ? string) int\n"
"func @\"\".slicestring (? string, ? int, ? int) string\n" "func @\"\".slicestring (? string, ? int, ? int) string\n"
"func @\"\".slicestring1 (? string, ? int) string\n" "func @\"\".slicestring1 (? string, ? int) string\n"

View File

@ -40,6 +40,7 @@ func concatstring()
// filled in by compiler: Type*, int n, Slice, ... // filled in by compiler: Type*, int n, Slice, ...
func append() func append()
func appendslice(typ *byte, x any, y []any) any func appendslice(typ *byte, x any, y []any) any
func appendstr(typ *byte, x []byte, y string) []byte
func cmpstring(string, string) int func cmpstring(string, string) int
func slicestring(string, int, int) string func slicestring(string, int, int) string

View File

@ -1008,6 +1008,10 @@ reswitch:
yyerror("too many arguments to append"); yyerror("too many arguments to append");
goto error; goto error;
} }
if(istype(t->type, TUINT8) && istype(args->next->n->type, TSTRING)) {
defaultlit(&args->next->n, types[TSTRING]);
goto ret;
}
args->next->n = assignconv(args->next->n, t->orig, "append"); args->next->n = assignconv(args->next->n, t->orig, "append");
goto ret; goto ret;
} }

View File

@ -925,7 +925,7 @@ walkexpr(Node **np, NodeList **init)
l, l,
nodintconst(t->type->width)); nodintconst(t->type->width));
} }
n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call. n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call.
goto ret; goto ret;
slicearray: slicearray:
@ -1056,8 +1056,12 @@ walkexpr(Node **np, NodeList **init)
goto ret; goto ret;
case OAPPEND: case OAPPEND:
if(n->isddd) if(n->isddd) {
n = appendslice(n, init); if(istype(n->type->type, TUINT8) && istype(n->list->next->n->type, TSTRING))
n = mkcall("appendstr", n->type, init, typename(n->type), n->list->n, n->list->next->n);
else
n = appendslice(n, init);
}
else else
n = append(n, init); n = append(n, init);
goto ret; goto ret;
@ -2111,7 +2115,7 @@ appendslice(Node *n, NodeList **init)
// s := src // s := src
// const argc = len(args) - 1 // const argc = len(args) - 1
// if cap(s) - len(s) < argc { // if cap(s) - len(s) < argc {
// s = growslice(s, argc) // s = growslice(s, argc)
// } // }
// n := len(s) // n := len(s)
// s = s[:n+argc] // s = s[:n+argc]
@ -2140,13 +2144,13 @@ append(Node *n, NodeList **init)
ns = temp(nsrc->type); ns = temp(nsrc->type);
l = list(l, nod(OAS, ns, nsrc)); // s = src l = list(l, nod(OAS, ns, nsrc)); // s = src
na = nodintconst(argc); // const argc na = nodintconst(argc); // const argc
nx = nod(OIF, N, N); // if cap(s) - len(s) < argc nx = nod(OIF, N, N); // if cap(s) - len(s) < argc
nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na); nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na);
fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T) fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T)
argtype(fn, ns->type->type); // 1 old []any argtype(fn, ns->type->type); // 1 old []any
argtype(fn, ns->type->type); // 2 ret []any argtype(fn, ns->type->type); // 2 ret []any
nx->nbody = list1(nod(OAS, ns, mkcall1(fn, ns->type, &nx->ninit, nx->nbody = list1(nod(OAS, ns, mkcall1(fn, ns->type, &nx->ninit,
typename(ns->type), typename(ns->type),
@ -2155,16 +2159,16 @@ append(Node *n, NodeList **init)
l = list(l, nx); l = list(l, nx);
nn = temp(types[TINT]); nn = temp(types[TINT]);
l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s) l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s)
nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc] nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc]
nx->etype = 1; // disable bounds check nx->etype = 1; // disable bounds check
l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc] l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc]
for (a = n->list->next; a != nil; a = a->next) { for (a = n->list->next; a != nil; a = a->next) {
nx = nod(OINDEX, ns, nn); // s[n] ... nx = nod(OINDEX, ns, nn); // s[n] ...
nx->etype = 1; // disable bounds check nx->etype = 1; // disable bounds check
l = list(l, nod(OAS, nx, a->n)); // s[n] = arg l = list(l, nod(OAS, nx, a->n)); // s[n] = arg
if (a->next != nil) if (a->next != nil)
l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))); // n = n + 1 l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))); // n = n + 1
} }

View File

@ -11,7 +11,6 @@ static int32 debug = 0;
static void makeslice1(SliceType*, int32, int32, Slice*); static void makeslice1(SliceType*, int32, int32, Slice*);
static void growslice1(SliceType*, Slice, int32, Slice *); static void growslice1(SliceType*, Slice, int32, Slice *);
static void appendslice1(SliceType*, Slice, Slice, Slice*);
void runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret); void runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret);
// see also unsafe·NewArray // see also unsafe·NewArray
@ -29,7 +28,7 @@ runtime·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
if(debug) { if(debug) {
runtime·printf("makeslice(%S, %D, %D); ret=", runtime·printf("makeslice(%S, %D, %D); ret=",
*t->string, len, cap); *t->string, len, cap);
runtime·printslice(ret); runtime·printslice(ret);
} }
} }
@ -52,12 +51,6 @@ makeslice1(SliceType *t, int32 len, int32 cap, Slice *ret)
// appendslice(type *Type, x, y, []T) []T // appendslice(type *Type, x, y, []T) []T
void void
runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret) runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret)
{
appendslice1(t, x, y, &ret);
}
static void
appendslice1(SliceType *t, Slice x, Slice y, Slice *ret)
{ {
int32 m; int32 m;
uintptr w; uintptr w;
@ -68,15 +61,39 @@ appendslice1(SliceType *t, Slice x, Slice y, Slice *ret)
runtime·throw("append: slice overflow"); runtime·throw("append: slice overflow");
if(m > x.cap) if(m > x.cap)
growslice1(t, x, m, ret); growslice1(t, x, m, &ret);
else else
*ret = x; ret = x;
w = t->elem->size; w = t->elem->size;
runtime·memmove(ret->array + ret->len*w, y.array, y.len*w); runtime·memmove(ret.array + ret.len*w, y.array, y.len*w);
ret->len += y.len; ret.len += y.len;
FLUSH(&ret);
} }
// appendstr([]byte, string) []byte
void
runtime·appendstr(SliceType *t, Slice x, String y, Slice ret)
{
int32 m;
m = x.len+y.len;
if(m < x.len)
runtime·throw("append: slice overflow");
if(m > x.cap)
growslice1(t, x, m, &ret);
else
ret = x;
runtime·memmove(ret.array + ret.len, y.str, y.len);
ret.len += y.len;
FLUSH(&ret);
}
// growslice(type *Type, x, []T, n int64) []T // growslice(type *Type, x, []T, n int64) []T
void void
runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret) runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
@ -97,9 +114,9 @@ runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
if(debug) { if(debug) {
runtime·printf("growslice(%S,", *t->string); runtime·printf("growslice(%S,", *t->string);
runtime·printslice(old); runtime·printslice(old);
runtime·printf(", new cap=%D) =", cap); runtime·printf(", new cap=%D) =", cap);
runtime·printslice(ret); runtime·printslice(ret);
} }
} }

View File

@ -63,6 +63,11 @@ var tests = []struct {
{"byte i", append([]byte{0, 1, 2}, []byte{3}...), []byte{0, 1, 2, 3}}, {"byte i", append([]byte{0, 1, 2}, []byte{3}...), []byte{0, 1, 2, 3}},
{"byte j", append([]byte{0, 1, 2}, []byte{3, 4, 5}...), []byte{0, 1, 2, 3, 4, 5}}, {"byte j", append([]byte{0, 1, 2}, []byte{3, 4, 5}...), []byte{0, 1, 2, 3, 4, 5}},
{"bytestr a", append([]byte{}, "0"...), []byte("0")},
{"bytestr b", append([]byte{}, "0123"...), []byte("0123")},
{"bytestr c", append([]byte("012"), "3"...), []byte("0123")},
{"bytestr d", append([]byte("012"), "345"...), []byte("012345")},
{"int16 a", append([]int16{}), []int16{}}, {"int16 a", append([]int16{}), []int16{}},
{"int16 b", append([]int16{}, 0), []int16{0}}, {"int16 b", append([]int16{}, 0), []int16{0}},