1
0
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:
Russ Cox 2010-10-27 17:56:32 -07:00
parent b803a255fc
commit d8b5d039cd
9 changed files with 171 additions and 14 deletions

View File

@ -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"

View File

@ -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,

View File

@ -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,

View File

@ -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:

View File

@ -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

View File

@ -810,6 +810,7 @@ goopnames[] =
[OANDAND] = "&&", [OANDAND] = "&&",
[OANDNOT] = "&^", [OANDNOT] = "&^",
[OAND] = "&", [OAND] = "&",
[OAPPEND] = "append",
[OAS] = "=", [OAS] = "=",
[OAS2] = "=", [OAS2] = "=",
[OBREAK] = "break", [OBREAK] = "break",

View File

@ -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;

View File

@ -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;
}

View File

@ -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)