gc: make string x + y + z + ... + w efficient

1 malloc per concatenation.

R=ken2
CC=golang-dev
https://golang.org/cl/2124045
This commit is contained in:
Russ Cox 2010-09-12 00:53:04 -04:00
parent 698fb4f192
commit f47d403cb4
5 changed files with 72 additions and 8 deletions

View File

@ -20,7 +20,7 @@ char *runtimeimport =
"func \"\".printnl ()\n"
"func \"\".printsp ()\n"
"func \"\".printf ()\n"
"func \"\".catstring (? string, ? string) string\n"
"func \"\".concatstring ()\n"
"func \"\".cmpstring (? string, ? string) int\n"
"func \"\".slicestring (? string, ? int, ? int) string\n"
"func \"\".slicestring1 (? string, ? int) string\n"

View File

@ -33,7 +33,9 @@ func printnl()
func printsp()
func printf()
func catstring(string, string) string
// filled in by compiler: int n, string, string, ...
func concatstring()
func cmpstring(string, string) int
func slicestring(string, int, int) string
func slicestring1(string, int) string

View File

@ -17,6 +17,7 @@ static void heapmoves(void);
static NodeList* paramstoheap(Type **argin, int out);
static NodeList* reorder1(NodeList*);
static NodeList* reorder3(NodeList*);
static Node* addstr(Node*, NodeList**);
static NodeList* walkdefstack;
@ -1205,10 +1206,7 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OADDSTR:
// sys_catstring(s1, s2)
n = mkcall("catstring", n->type, init,
conv(n->left, types[TSTRING]),
conv(n->right, types[TSTRING]));
n = addstr(n, init);
goto ret;
case OSLICESTR:
@ -2234,3 +2232,42 @@ mapfn(char *name, Type *t)
argtype(fn, t->type);
return fn;
}
static Node*
addstr(Node *n, NodeList **init)
{
Node *r, *cat, *typstr;
NodeList *in, *args;
int i, count;
count = 0;
for(r=n; r->op == OADDSTR; r=r->left)
count++; // r->right
count++; // r
// prepare call of runtime.catstring of type int, string, string, string
// with as many strings as we have.
cat = syslook("concatstring", 1);
cat->type = T;
cat->ntype = nod(OTFUNC, N, N);
in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // count
typstr = typenod(types[TSTRING]);
for(i=0; i<count; i++)
in = list(in, nod(ODCLFIELD, N, typstr));
cat->ntype->list = in;
cat->ntype->rlist = list1(nod(ODCLFIELD, N, typstr));
args = nil;
for(r=n; r->op == OADDSTR; r=r->left)
args = concat(list1(conv(r->right, types[TSTRING])), args);
args = concat(list1(conv(r, types[TSTRING])), args);
args = concat(list1(nodintconst(count)), args);
r = nod(OCALL, cat, N);
r->list = args;
typecheck(&r, Erv);
walkexpr(&r, init);
r->type = n->type;
return r;
}

View File

@ -395,6 +395,7 @@ void memmove(void*, void*, uint32);
void* mal(uintptr);
uint32 cmpstring(String, String);
String catstring(String, String);
String concatstring(int32, String*);
String gostring(byte*);
String gostringn(byte*, int32);
String gostringnocopy(byte*);

View File

@ -114,9 +114,33 @@ catstring(String s1, String s2)
return s3;
}
String
concatstring(int32 n, String *s)
{
int32 i, l;
String out;
func catstring(s1 String, s2 String) (s3 String) {
s3 = catstring(s1, s2);
l = 0;
for(i=0; i<n; i++) {
if(l + s[i].len < l)
throw("string concatenation too long");
l += s[i].len;
}
out = gostringsize(l);
l = 0;
for(i=0; i<n; i++) {
mcpy(out.str+l, s[i].str, s[i].len);
l += s[i].len;
}
return out;
}
#pragma textflag 7
// s1 is the first of n strings.
// the output string follows.
func concatstring(n int32, s1 String) {
(&s1)[n] = concatstring(n, &s1);
}
uint32