mirror of
https://github.com/golang/go
synced 2024-11-19 03:44:40 -07:00
gc: implement append
R=ken2 CC=golang-dev https://golang.org/cl/2757042
This commit is contained in:
parent
b803a255fc
commit
d8b5d039cd
@ -21,6 +21,8 @@ char *runtimeimport =
|
|||||||
"func \"\".printsp ()\n"
|
"func \"\".printsp ()\n"
|
||||||
"func \"\".printf ()\n"
|
"func \"\".printf ()\n"
|
||||||
"func \"\".concatstring ()\n"
|
"func \"\".concatstring ()\n"
|
||||||
|
"func \"\".append ()\n"
|
||||||
|
"func \"\".appendslice (typ *uint8, x any, y []any) any\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"
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <bio.h>
|
#include <bio.h>
|
||||||
|
|
||||||
|
#undef OAPPEND
|
||||||
|
|
||||||
// avoid <ctype.h>
|
// avoid <ctype.h>
|
||||||
#undef isblank
|
#undef isblank
|
||||||
#define isblank goisblank
|
#define isblank goisblank
|
||||||
@ -349,6 +351,7 @@ enum
|
|||||||
OADD, OSUB, OOR, OXOR, OADDSTR,
|
OADD, OSUB, OOR, OXOR, OADDSTR,
|
||||||
OADDR,
|
OADDR,
|
||||||
OANDAND,
|
OANDAND,
|
||||||
|
OAPPEND,
|
||||||
OARRAY,
|
OARRAY,
|
||||||
OARRAYBYTESTR, OARRAYRUNESTR,
|
OARRAYBYTESTR, OARRAYRUNESTR,
|
||||||
OSTRARRAYBYTE, OSTRARRAYRUNE,
|
OSTRARRAYBYTE, OSTRARRAYRUNE,
|
||||||
|
@ -1531,6 +1531,7 @@ static struct
|
|||||||
"type", LTYPE, Txxx, OXXX,
|
"type", LTYPE, Txxx, OXXX,
|
||||||
"var", LVAR, Txxx, OXXX,
|
"var", LVAR, Txxx, OXXX,
|
||||||
|
|
||||||
|
"append", LNAME, Txxx, OAPPEND,
|
||||||
"cap", LNAME, Txxx, OCAP,
|
"cap", LNAME, Txxx, OCAP,
|
||||||
"close", LNAME, Txxx, OCLOSE,
|
"close", LNAME, Txxx, OCLOSE,
|
||||||
"closed", LNAME, Txxx, OCLOSED,
|
"closed", LNAME, Txxx, OCLOSED,
|
||||||
|
@ -37,6 +37,7 @@ exprfmt(Fmt *f, Node *n, int prec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch(n->op) {
|
switch(n->op) {
|
||||||
|
case OAPPEND:
|
||||||
case ONAME:
|
case ONAME:
|
||||||
case ONONAME:
|
case ONONAME:
|
||||||
case OPACK:
|
case OPACK:
|
||||||
@ -400,6 +401,7 @@ exprfmt(Fmt *f, Node *n, int prec)
|
|||||||
fmtprint(f, ")");
|
fmtprint(f, ")");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OAPPEND:
|
||||||
case OCAP:
|
case OCAP:
|
||||||
case OCLOSE:
|
case OCLOSE:
|
||||||
case OCLOSED:
|
case OCLOSED:
|
||||||
|
@ -36,6 +36,10 @@ func printf()
|
|||||||
// filled in by compiler: int n, string, string, ...
|
// filled in by compiler: int n, string, string, ...
|
||||||
func concatstring()
|
func concatstring()
|
||||||
|
|
||||||
|
// filled in by compiler: Type*, int n, Slice, ...
|
||||||
|
func append()
|
||||||
|
func appendslice(typ *byte, x any, y []any) any
|
||||||
|
|
||||||
func cmpstring(string, string) int
|
func cmpstring(string, string) int
|
||||||
func slicestring(string, int, int) string
|
func slicestring(string, int, int) string
|
||||||
func slicestring1(string, int) string
|
func slicestring1(string, int) string
|
||||||
|
@ -810,6 +810,7 @@ goopnames[] =
|
|||||||
[OANDAND] = "&&",
|
[OANDAND] = "&&",
|
||||||
[OANDNOT] = "&^",
|
[OANDNOT] = "&^",
|
||||||
[OAND] = "&",
|
[OAND] = "&",
|
||||||
|
[OAPPEND] = "append",
|
||||||
[OAS] = "=",
|
[OAS] = "=",
|
||||||
[OAS2] = "=",
|
[OAS2] = "=",
|
||||||
[OBREAK] = "break",
|
[OBREAK] = "break",
|
||||||
|
@ -730,7 +730,7 @@ reswitch:
|
|||||||
typecheck(&n->left, Erv | Etype | Ecall);
|
typecheck(&n->left, Erv | Etype | Ecall);
|
||||||
l = n->left;
|
l = n->left;
|
||||||
if(l->op == ONAME && l->etype != 0) {
|
if(l->op == ONAME && l->etype != 0) {
|
||||||
if(n->isddd)
|
if(n->isddd && l->etype != OAPPEND)
|
||||||
yyerror("invalid use of ... with builtin %#N", l);
|
yyerror("invalid use of ... with builtin %#N", l);
|
||||||
// builtin: OLEN, OCAP, etc.
|
// builtin: OLEN, OCAP, etc.
|
||||||
n->op = l->etype;
|
n->op = l->etype;
|
||||||
@ -905,6 +905,40 @@ reswitch:
|
|||||||
ok |= Etop;
|
ok |= Etop;
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
|
case OAPPEND:
|
||||||
|
ok |= Erv;
|
||||||
|
args = n->list;
|
||||||
|
if(args == nil) {
|
||||||
|
yyerror("missing arguments to append");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
typechecklist(args, Erv);
|
||||||
|
if((t = args->n->type) == T)
|
||||||
|
goto error;
|
||||||
|
n->type = t;
|
||||||
|
if(!isslice(t)) {
|
||||||
|
yyerror("first argument to append must be slice; have %lT", t);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if(n->isddd) {
|
||||||
|
if(args->next == nil) {
|
||||||
|
yyerror("cannot use ... on first argument to append");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if(args->next->next != nil) {
|
||||||
|
yyerror("too many arguments to append");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
args->next->n = assignconv(args->next->n, t->orig, "append");
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
for(args=args->next; args != nil; args=args->next) {
|
||||||
|
if(args->n->type == T)
|
||||||
|
continue;
|
||||||
|
args->n = assignconv(args->n, t->type, "append");
|
||||||
|
}
|
||||||
|
goto ret;
|
||||||
|
|
||||||
case OCOPY:
|
case OCOPY:
|
||||||
ok |= Etop|Erv;
|
ok |= Etop|Erv;
|
||||||
args = n->list;
|
args = n->list;
|
||||||
|
@ -18,6 +18,7 @@ static NodeList* paramstoheap(Type **argin, int out);
|
|||||||
static NodeList* reorder1(NodeList*);
|
static NodeList* reorder1(NodeList*);
|
||||||
static NodeList* reorder3(NodeList*);
|
static NodeList* reorder3(NodeList*);
|
||||||
static Node* addstr(Node*, NodeList**);
|
static Node* addstr(Node*, NodeList**);
|
||||||
|
static Node* append(Node*, NodeList**);
|
||||||
|
|
||||||
static NodeList* walkdefstack;
|
static NodeList* walkdefstack;
|
||||||
|
|
||||||
@ -1264,6 +1265,10 @@ walkexpr(Node **np, NodeList **init)
|
|||||||
l);
|
l);
|
||||||
}
|
}
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
|
case OAPPEND:
|
||||||
|
n = append(n, init);
|
||||||
|
goto ret;
|
||||||
|
|
||||||
case OCOPY:
|
case OCOPY:
|
||||||
if(n->right->type->etype == TSTRING)
|
if(n->right->type->etype == TSTRING)
|
||||||
@ -2304,3 +2309,44 @@ addstr(Node *n, NodeList **init)
|
|||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Node*
|
||||||
|
append(Node *n, NodeList **init)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
Node *f, *r;
|
||||||
|
NodeList *in, *args;
|
||||||
|
|
||||||
|
if(n->isddd) {
|
||||||
|
f = syslook("appendslice", 1);
|
||||||
|
argtype(f, n->type);
|
||||||
|
argtype(f, n->type->type);
|
||||||
|
argtype(f, n->type);
|
||||||
|
r = mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
j = count(n->list) - 1;
|
||||||
|
f = syslook("append", 1);
|
||||||
|
f->type = T;
|
||||||
|
f->ntype = nod(OTFUNC, N, N);
|
||||||
|
in = list1(nod(ODCLFIELD, N, typenod(ptrto(types[TUINT8])))); // type
|
||||||
|
in = list(in, nod(ODCLFIELD, N, typenod(types[TINT]))); // count
|
||||||
|
in = list(in, nod(ODCLFIELD, N, typenod(n->type))); // slice
|
||||||
|
for(i=0; i<j; i++)
|
||||||
|
in = list(in, nod(ODCLFIELD, N, typenod(n->type->type)));
|
||||||
|
f->ntype->list = in;
|
||||||
|
f->ntype->rlist = list1(nod(ODCLFIELD, N, typenod(n->type)));
|
||||||
|
|
||||||
|
args = list1(typename(n->type));
|
||||||
|
args = list(args, nodintconst(j));
|
||||||
|
args = concat(args, n->list);
|
||||||
|
|
||||||
|
r = nod(OCALL, f, N);
|
||||||
|
r->list = args;
|
||||||
|
typecheck(&r, Erv);
|
||||||
|
walkexpr(&r, init);
|
||||||
|
r->type = n->type;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
@ -8,29 +8,20 @@
|
|||||||
|
|
||||||
static int32 debug = 0;
|
static int32 debug = 0;
|
||||||
|
|
||||||
|
static void makeslice(SliceType*, int32, int32, Slice*);
|
||||||
|
void ·slicecopy(Slice to, Slice fm, uintptr width, int32 ret);
|
||||||
|
|
||||||
// see also unsafe·NewArray
|
// see also unsafe·NewArray
|
||||||
// makeslice(typ *Type, len, cap int64) (ary []any);
|
// makeslice(typ *Type, len, cap int64) (ary []any);
|
||||||
void
|
void
|
||||||
·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
|
·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
|
||||||
{
|
{
|
||||||
uintptr size;
|
|
||||||
|
|
||||||
if(len < 0 || (int32)len != len)
|
if(len < 0 || (int32)len != len)
|
||||||
panicstring("makeslice: len out of range");
|
panicstring("makeslice: len out of range");
|
||||||
if(cap < len || (int32)cap != cap || cap > ((uintptr)-1) / t->elem->size)
|
if(cap < len || (int32)cap != cap || cap > ((uintptr)-1) / t->elem->size)
|
||||||
panicstring("makeslice: cap out of range");
|
panicstring("makeslice: cap out of range");
|
||||||
|
|
||||||
size = cap*t->elem->size;
|
makeslice(t, len, cap, &ret);
|
||||||
|
|
||||||
ret.len = len;
|
|
||||||
ret.cap = cap;
|
|
||||||
|
|
||||||
if((t->elem->kind&KindNoPointers))
|
|
||||||
ret.array = mallocgc(size, RefNoPointers, 1, 1);
|
|
||||||
else
|
|
||||||
ret.array = mal(size);
|
|
||||||
|
|
||||||
FLUSH(&ret);
|
|
||||||
|
|
||||||
if(debug) {
|
if(debug) {
|
||||||
printf("makeslice(%S, %D, %D); ret=",
|
printf("makeslice(%S, %D, %D); ret=",
|
||||||
@ -39,6 +30,79 @@ void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
makeslice(SliceType *t, int32 len, int32 cap, Slice *ret)
|
||||||
|
{
|
||||||
|
uintptr size;
|
||||||
|
|
||||||
|
size = cap*t->elem->size;
|
||||||
|
|
||||||
|
ret->len = len;
|
||||||
|
ret->cap = cap;
|
||||||
|
|
||||||
|
if((t->elem->kind&KindNoPointers))
|
||||||
|
ret->array = mallocgc(size, RefNoPointers, 1, 1);
|
||||||
|
else
|
||||||
|
ret->array = mal(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void appendslice(SliceType*, Slice, Slice, Slice*);
|
||||||
|
|
||||||
|
// append(type *Type, n int, old []T, ...,) []T
|
||||||
|
#pragma textflag 7
|
||||||
|
void
|
||||||
|
·append(SliceType *t, int32 n, Slice old, ...)
|
||||||
|
{
|
||||||
|
Slice sl;
|
||||||
|
Slice *ret;
|
||||||
|
|
||||||
|
sl.len = n;
|
||||||
|
sl.array = (byte*)(&old+1);
|
||||||
|
ret = (Slice*)(sl.array + ((t->elem->size*n+sizeof(uintptr)-1) & ~(sizeof(uintptr)-1)));
|
||||||
|
appendslice(t, old, sl, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendslice(type *Type, x, y, []T) []T
|
||||||
|
void
|
||||||
|
·appendslice(SliceType *t, Slice x, Slice y, Slice ret)
|
||||||
|
{
|
||||||
|
appendslice(t, x, y, &ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
appendslice(SliceType *t, Slice x, Slice y, Slice *ret)
|
||||||
|
{
|
||||||
|
Slice newx;
|
||||||
|
int32 m;
|
||||||
|
uintptr w;
|
||||||
|
|
||||||
|
if(x.len+y.len < x.len)
|
||||||
|
throw("append: slice overflow");
|
||||||
|
|
||||||
|
w = t->elem->size;
|
||||||
|
if(x.len+y.len > x.cap) {
|
||||||
|
m = x.cap;
|
||||||
|
if(m == 0)
|
||||||
|
m = y.len;
|
||||||
|
else {
|
||||||
|
do {
|
||||||
|
if(x.len < 1024)
|
||||||
|
m += m;
|
||||||
|
else
|
||||||
|
m += m/4;
|
||||||
|
} while(m < x.len+y.len);
|
||||||
|
}
|
||||||
|
makeslice(t, x.len, m, &newx);
|
||||||
|
memmove(newx.array, x.array, x.len*w);
|
||||||
|
x = newx;
|
||||||
|
}
|
||||||
|
memmove(x.array+x.len*w, y.array, y.len*w);
|
||||||
|
x.len += y.len;
|
||||||
|
*ret = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any);
|
// sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any);
|
||||||
void
|
void
|
||||||
·sliceslice(Slice old, uint64 lb, uint64 hb, uint64 width, Slice ret)
|
·sliceslice(Slice old, uint64 lb, uint64 hb, uint64 width, Slice ret)
|
||||||
|
Loading…
Reference in New Issue
Block a user