gc: implement []int(string) and []byte(string)

R=ken2
CC=golang-dev
https://golang.org/cl/224060
This commit is contained in:
Russ Cox 2010-02-25 15:11:07 -08:00
parent b86c0b0c4a
commit 3910161307
8 changed files with 175 additions and 14 deletions

View file

@ -26,6 +26,8 @@ char *runtimeimport =
"func \"\".intstring (? int64) string\n" "func \"\".intstring (? int64) string\n"
"func \"\".slicebytetostring (? []uint8) string\n" "func \"\".slicebytetostring (? []uint8) string\n"
"func \"\".sliceinttostring (? []int) string\n" "func \"\".sliceinttostring (? []int) string\n"
"func \"\".stringtoslicebyte (? string) []uint8\n"
"func \"\".stringtosliceint (? string) []int\n"
"func \"\".stringiter (? string, ? int) int\n" "func \"\".stringiter (? string, ? int) int\n"
"func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n" "func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n"
"func \"\".slicecopy (to any, fr any, wid uint32) int\n" "func \"\".slicecopy (to any, fr any, wid uint32) int\n"

View file

@ -351,6 +351,7 @@ enum
OAPPENDSTR, OAPPENDSTR,
OARRAY, OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR, OARRAYBYTESTR, OARRAYRUNESTR,
OSTRARRAYBYTE, OSTRARRAYRUNE,
OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP, OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
OBAD, OBAD,
OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,

View file

@ -38,6 +38,8 @@ func indexstring(string, int) byte
func intstring(int64) string func intstring(int64) string
func slicebytetostring([]byte) string func slicebytetostring([]byte) string
func sliceinttostring([]int) string func sliceinttostring([]int) string
func stringtoslicebyte(string) []byte
func stringtosliceint(string) []int
func stringiter(string, int) int func stringiter(string, int) int
func stringiter2(string, int) (retk int, retv int) func stringiter2(string, int) (retk int, retv int)
func slicecopy(to any, fr any, wid uint32) int func slicecopy(to any, fr any, wid uint32) int

View file

@ -32,6 +32,7 @@ static void checklvalue(Node*, char*);
static void checkassign(Node*); static void checkassign(Node*);
static void checkassignlist(NodeList*); static void checkassignlist(NodeList*);
static void toslice(Node**); static void toslice(Node**);
static void stringtoarraylit(Node**);
void void
typechecklist(NodeList *l, int top) typechecklist(NodeList *l, int top)
@ -835,6 +836,13 @@ reswitch:
n = typecheckconv(n, n->left, n->type, 1, "conversion"); n = typecheckconv(n, n->left, n->type, 1, "conversion");
if(n->type == T) if(n->type == T)
goto error; goto error;
switch(n->op) {
case OSTRARRAYBYTE:
case OSTRARRAYRUNE:
if(n->left->op == OLITERAL)
stringtoarraylit(&n);
break;
}
goto ret; goto ret;
case OMAKE: case OMAKE:
@ -1406,6 +1414,18 @@ checkconv(Type *nt, Type *t, int explicit, int *op, int *et, char *desc)
} }
} }
// from string
if(istype(nt, TSTRING) && isslice(t) && t->sym == S) {
switch(t->type->etype) {
case TUINT8:
*op = OSTRARRAYBYTE;
return 1;
case TINT:
*op = OSTRARRAYRUNE;
return 1;
}
}
// convert to unsafe pointer // convert to unsafe pointer
if(isptrto(t, TANY) if(isptrto(t, TANY)
&& (isptr[nt->etype] || nt->etype == TUINTPTR)) && (isptr[nt->etype] || nt->etype == TUINTPTR))
@ -2164,3 +2184,39 @@ typecheckfunc(Node *n)
if(rcvr != nil && n->shortname != N && !isblank(n->shortname)) if(rcvr != nil && n->shortname != N && !isblank(n->shortname))
addmethod(n->shortname->sym, t, 1); addmethod(n->shortname->sym, t, 1);
} }
static void
stringtoarraylit(Node **np)
{
int32 i;
NodeList *l;
Strlit *s;
char *p, *ep;
Rune r;
Node *nn, *n;
n = *np;
if(n->left->op != OLITERAL || n->left->val.ctype != CTSTR)
fatal("stringtoarraylit %N", n);
s = n->left->val.u.sval;
l = nil;
p = s->s;
ep = s->s + s->len;
i = 0;
if(n->type->type->etype == TUINT8) {
// raw []byte
while(p < ep)
l = list(l, nod(OKEY, nodintconst(i++), nodintconst((uchar)*p++)));
} else {
// utf-8 []int
while(p < ep) {
p += chartorune(&r, p);
l = list(l, nod(OKEY, nodintconst(i++), nodintconst(r)));
}
}
nn = nod(OCOMPLIT, N, typenod(n->type));
nn->list = l;
typecheck(&nn, Erv);
*np = nn;
}

View file

@ -8,6 +8,7 @@ static Node* walkprint(Node*, NodeList**, int);
static Node* conv(Node*, Type*); static Node* conv(Node*, Type*);
static Node* mapfn(char*, Type*); static Node* mapfn(char*, Type*);
static Node* makenewvar(Type*, NodeList**, Node**); static Node* makenewvar(Type*, NodeList**, Node**);
enum enum
{ {
Inone, Inone,
@ -1092,10 +1093,20 @@ walkexpr(Node **np, NodeList **init)
goto ret; goto ret;
case OARRAYRUNESTR: case OARRAYRUNESTR:
// sliceinttostring([]byte) string; // sliceinttostring([]int) string;
n = mkcall("sliceinttostring", n->type, init, n->left); n = mkcall("sliceinttostring", n->type, init, n->left);
goto ret; goto ret;
case OSTRARRAYBYTE:
// stringtoslicebyte(string) []byte;
n = mkcall("stringtoslicebyte", n->type, init, n->left);
goto ret;
case OSTRARRAYRUNE:
// stringtosliceint(string) []int
n = mkcall("stringtosliceint", n->type, init, n->left);
goto ret;
case OCMPIFACE: case OCMPIFACE:
// ifaceeq(i1 any-1, i2 any-2) (ret bool); // ifaceeq(i1 any-1, i2 any-2) (ret bool);
if(!eqtype(n->left->type, n->right->type)) if(!eqtype(n->left->type, n->right->type))
@ -1117,6 +1128,7 @@ walkexpr(Node **np, NodeList **init)
case OARRAYLIT: case OARRAYLIT:
case OMAPLIT: case OMAPLIT:
case OSTRUCTLIT: case OSTRUCTLIT:
arraylit:
nvar = nod(OXXX, N, N); nvar = nod(OXXX, N, N);
tempname(nvar, n->type); tempname(nvar, n->type);
anylit(n, nvar, init); anylit(n, nvar, init);

View file

@ -4,6 +4,7 @@
package runtime package runtime
#include "runtime.h" #include "runtime.h"
#include "malloc.h"
String emptystring; String emptystring;
@ -210,6 +211,12 @@ func slicebytetostring(b Slice) (s String) {
mcpy(s.str, b.array, s.len); mcpy(s.str, b.array, s.len);
} }
func stringtoslicebyte(s String) (b Slice) {
b.array = mallocgc(s.len, RefNoPointers, 1, 1);
b.len = s.len;
b.cap = s.len;
mcpy(b.array, s.str, s.len);
}
func sliceinttostring(b Slice) (s String) { func sliceinttostring(b Slice) (s String) {
int32 siz1, siz2, i; int32 siz1, siz2, i;
@ -233,6 +240,30 @@ func sliceinttostring(b Slice) (s String) {
s.len = siz2; s.len = siz2;
} }
func stringtosliceint(s String) (b Slice) {
int32 n;
int32 dum, *r;
uint8 *p, *ep;
// two passes.
// unlike sliceinttostring, no race because strings are immutable.
p = s.str;
ep = s.str+s.len;
n = 0;
while(p < ep) {
p += charntorune(&dum, p, ep-p);
n++;
}
b.array = mallocgc(n*sizeof(r[0]), RefNoPointers, 1, 1);
b.len = n;
b.cap = n;
p = s.str;
r = (int32*)b.array;
while(p < ep)
p += charntorune(r++, p, ep-p);
}
enum enum
{ {
Runeself = 0x80, Runeself = 0x80,

View file

@ -35,3 +35,30 @@ var good2 int = 1.0;
var good3 int = 1e9; var good3 int = 1e9;
var good4 float = 1e20; var good4 float = 1e20;
// explicit conversion of string is okay
var _ = []int("abc")
var _ = []byte("abc")
// implicit is not
var _ []int = "abc" // ERROR "cannot use|incompatible|invalid"
var _ []byte = "abc" // ERROR "cannot use|incompatible|invalid"
// named string is okay
type Tstring string
var ss Tstring = "abc"
var _ = []int(ss)
var _ = []byte(ss)
// implicit is still not
var _ []int = ss // ERROR "cannot use|incompatible|invalid"
var _ []byte = ss // ERROR "cannot use|incompatible|invalid"
// named slice is not
type Tint []int
type Tbyte []byte
var _ = Tint("abc") // ERROR "convert|incompatible|invalid"
var _ = Tbyte("abc") // ERROR "convert|incompatible|invalid"
// implicit is still not
var _ Tint = "abc" // ERROR "cannot use|incompatible|invalid"
var _ Tbyte = "abc" // ERROR "cannot use|incompatible|invalid"

View file

@ -34,6 +34,19 @@ func assert(a, b, c string) {
} }
} }
const (
gx1 = "aä本☺"
gx2 = "aä\xFF\xFF本☺"
gx2fix = "aä\uFFFD\uFFFD本☺"
)
var (
gr1 = []int(gx1)
gr2 = []int(gx2)
gb1 = []byte(gx1)
gb2 = []byte(gx2)
)
func main() { func main() {
ecode = 0; ecode = 0;
s := s :=
@ -86,5 +99,22 @@ func main() {
r = 0x10ffff + 1; r = 0x10ffff + 1;
s = string(r); s = string(r);
assert(s, "\xef\xbf\xbd", "too-large rune"); assert(s, "\xef\xbf\xbd", "too-large rune");
assert(string(gr1), gx1, "global ->[]int")
assert(string(gr2), gx2fix, "global invalid ->[]int")
assert(string(gb1), gx1, "->[]byte")
assert(string(gb2), gx2, "global invalid ->[]byte")
var (
r1 = []int(gx1)
r2 = []int(gx2)
b1 = []byte(gx1)
b2 = []byte(gx2)
)
assert(string(r1), gx1, "->[]int")
assert(string(r2), gx2fix, "invalid ->[]int")
assert(string(b1), gx1, "->[]byte")
assert(string(b2), gx2, "invalid ->[]byte")
os.Exit(ecode); os.Exit(ecode);
} }