"func \"\".printsp ()\n"
"func \"\".printf ()\n"
"func \"\".concatstring ()\n"
+ "func \"\".append ()\n"
+ "func \"\".appendslice (typ *uint8, x any, y []any) any\n"
"func \"\".cmpstring (? string, ? string) int\n"
"func \"\".slicestring (? string, ? int, ? int) string\n"
"func \"\".slicestring1 (? string, ? int) string\n"
#include <libc.h>
#include <bio.h>
+#undef OAPPEND
+
// avoid <ctype.h>
#undef isblank
#define isblank goisblank
OADD, OSUB, OOR, OXOR, OADDSTR,
OADDR,
OANDAND,
+ OAPPEND,
OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR,
OSTRARRAYBYTE, OSTRARRAYRUNE,
"type", LTYPE, Txxx, OXXX,
"var", LVAR, Txxx, OXXX,
+ "append", LNAME, Txxx, OAPPEND,
"cap", LNAME, Txxx, OCAP,
"close", LNAME, Txxx, OCLOSE,
"closed", LNAME, Txxx, OCLOSED,
}
switch(n->op) {
+ case OAPPEND:
case ONAME:
case ONONAME:
case OPACK:
fmtprint(f, ")");
break;
+ case OAPPEND:
case OCAP:
case OCLOSE:
case OCLOSED:
// filled in by compiler: int n, string, string, ...
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 slicestring(string, int, int) string
func slicestring1(string, int) string
[OANDAND] = "&&",
[OANDNOT] = "&^",
[OAND] = "&",
+ [OAPPEND] = "append",
[OAS] = "=",
[OAS2] = "=",
[OBREAK] = "break",
typecheck(&n->left, Erv | Etype | Ecall);
l = n->left;
if(l->op == ONAME && l->etype != 0) {
- if(n->isddd)
+ if(n->isddd && l->etype != OAPPEND)
yyerror("invalid use of ... with builtin %#N", l);
// builtin: OLEN, OCAP, etc.
n->op = l->etype;
ok |= Etop;
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:
ok |= Etop|Erv;
args = n->list;
static NodeList* reorder1(NodeList*);
static NodeList* reorder3(NodeList*);
static Node* addstr(Node*, NodeList**);
+static Node* append(Node*, NodeList**);
static NodeList* walkdefstack;
l);
}
goto ret;
+
+ case OAPPEND:
+ n = append(n, init);
+ goto ret;
case OCOPY:
if(n->right->type->etype == TSTRING)
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;
+}
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
// makeslice(typ *Type, len, cap int64) (ary []any);
void
·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
{
- uintptr size;
-
if(len < 0 || (int32)len != len)
panicstring("makeslice: len out of range");
if(cap < len || (int32)cap != cap || cap > ((uintptr)-1) / t->elem->size)
panicstring("makeslice: cap out of range");
+ makeslice(t, len, cap, &ret);
+
+ if(debug) {
+ printf("makeslice(%S, %D, %D); ret=",
+ *t->string, len, cap);
+ ·printslice(ret);
+ }
+}
+
+static void
+makeslice(SliceType *t, int32 len, int32 cap, Slice *ret)
+{
+ uintptr size;
+
size = cap*t->elem->size;
- ret.len = len;
- ret.cap = cap;
+ ret->len = len;
+ ret->cap = cap;
if((t->elem->kind&KindNoPointers))
- ret.array = mallocgc(size, RefNoPointers, 1, 1);
+ ret->array = mallocgc(size, RefNoPointers, 1, 1);
else
- ret.array = mal(size);
+ ret->array = mal(size);
+}
- FLUSH(&ret);
+static void appendslice(SliceType*, Slice, Slice, Slice*);
- if(debug) {
- printf("makeslice(%S, %D, %D); ret=",
- *t->string, len, cap);
- ·printslice(ret);
+// 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);
void
·sliceslice(Slice old, uint64 lb, uint64 hb, uint64 width, Slice ret)