]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: reconstitute runetochar for use by gostringw.
authorKeith Randall <khr@golang.org>
Tue, 17 Jun 2014 07:36:23 +0000 (00:36 -0700)
committerKeith Randall <khr@golang.org>
Tue, 17 Jun 2014 07:36:23 +0000 (00:36 -0700)
Fixes windows builds (hopefully).

LGTM=bradfitz
R=golang-codereviews, bradfitz, alex.brainman
CC=golang-codereviews
https://golang.org/cl/103470045

src/pkg/runtime/export_test.go
src/pkg/runtime/string.c
src/pkg/runtime/string_test.go
src/pkg/runtime/stubs.goc

index 7a31b63b31fca74f3ecee1e28edc0097e20ab38c..72d4e110865b21ddff469794f85d80bd9432d145 100644 (file)
@@ -90,3 +90,7 @@ var MemclrBytes = memclrBytes
 func gogoBytes() int32
 
 var GogoBytes = gogoBytes
+
+func gostringW([]byte) string
+
+var GostringW = gostringW
index d5b668bd614ff2073d20deec92762d158498a9c4..60a0545a9a5a964a2ee6f5b3e0c4af0d17cb2a6a 100644 (file)
@@ -100,6 +100,94 @@ runtime·gostringnocopy(byte *str)
        return s;
 }
 
+// TODO: move this elsewhere
+enum
+{
+       Bit1    = 7,
+       Bitx    = 6,
+       Bit2    = 5,
+       Bit3    = 4,
+       Bit4    = 3,
+       Bit5    = 2,
+
+       Tx      = ((1<<(Bitx+1))-1) ^ 0xFF,     /* 1000 0000 */
+       T2      = ((1<<(Bit2+1))-1) ^ 0xFF,     /* 1100 0000 */
+       T3      = ((1<<(Bit3+1))-1) ^ 0xFF,     /* 1110 0000 */
+       T4      = ((1<<(Bit4+1))-1) ^ 0xFF,     /* 1111 0000 */
+
+       Rune1   = (1<<(Bit1+0*Bitx))-1,         /* 0000 0000 0111 1111 */
+       Rune2   = (1<<(Bit2+1*Bitx))-1,         /* 0000 0111 1111 1111 */
+       Rune3   = (1<<(Bit3+2*Bitx))-1,         /* 1111 1111 1111 1111 */
+
+       Maskx   = (1<<Bitx)-1,                  /* 0011 1111 */
+
+       Runeerror       = 0xFFFD,
+
+       SurrogateMin = 0xD800,
+       SurrogateMax = 0xDFFF,
+
+       Runemax = 0x10FFFF,     /* maximum rune value */
+};
+
+static int32
+runetochar(byte *str, int32 rune)  /* note: in original, arg2 was pointer */
+{
+       /* Runes are signed, so convert to unsigned for range check. */
+       uint32 c;
+
+       /*
+        * one character sequence
+        *      00000-0007F => 00-7F
+        */
+       c = rune;
+       if(c <= Rune1) {
+               str[0] = c;
+               return 1;
+       }
+
+       /*
+        * two character sequence
+        *      0080-07FF => T2 Tx
+        */
+       if(c <= Rune2) {
+               str[0] = T2 | (c >> 1*Bitx);
+               str[1] = Tx | (c & Maskx);
+               return 2;
+       }
+
+       /*
+        * If the Rune is out of range or a surrogate half, convert it to the error rune.
+        * Do this test here because the error rune encodes to three bytes.
+        * Doing it earlier would duplicate work, since an out of range
+        * Rune wouldn't have fit in one or two bytes.
+        */
+       if (c > Runemax)
+               c = Runeerror;
+       if (SurrogateMin <= c && c <= SurrogateMax)
+               c = Runeerror;
+
+       /*
+        * three character sequence
+        *      0800-FFFF => T3 Tx Tx
+        */
+       if (c <= Rune3) {
+               str[0] = T3 |  (c >> 2*Bitx);
+               str[1] = Tx | ((c >> 1*Bitx) & Maskx);
+               str[2] = Tx |  (c & Maskx);
+               return 3;
+       }
+
+       /*
+        * four character sequence (21-bit value)
+        *     10000-1FFFFF => T4 Tx Tx Tx
+        */
+       str[0] = T4 | (c >> 3*Bitx);
+       str[1] = Tx | ((c >> 2*Bitx) & Maskx);
+       str[2] = Tx | ((c >> 1*Bitx) & Maskx);
+       str[3] = Tx | (c & Maskx);
+       return 4;
+}
+
 String
 runtime·gostringw(uint16 *str)
 {
@@ -109,14 +197,14 @@ runtime·gostringw(uint16 *str)
 
        n1 = 0;
        for(i=0; str[i]; i++)
-               n1 += runtime·runetochar(buf, str[i]);
+               n1 += runetochar(buf, str[i]);
        s = gostringsize(n1+4);
        n2 = 0;
        for(i=0; str[i]; i++) {
                // check for race
                if(n2 >= n1)
                        break;
-               n2 += runtime·runetochar(s.str+n2, str[i]);
+               n2 += runetochar(s.str+n2, str[i]);
        }
        s.len = n2;
        s.str[s.len] = 0;
index dbccc24a5bc20c79218e38737ed5993792d769e8..28a5c6bd1e80f526c2f69b9a3a8dff9a9f16581a 100644 (file)
@@ -5,6 +5,7 @@
 package runtime_test
 
 import (
+       "runtime"
        "testing"
 )
 
@@ -99,3 +100,25 @@ func BenchmarkRuneIterate2(b *testing.B) {
                }
        }
 }
+
+func TestStringW(t *testing.T) {
+       strings := []string{
+               "hello",
+               "a\u5566\u7788\b",
+       }
+
+       for _, s := range strings {
+               var b []byte
+               for _, c := range s {
+                       b = append(b, byte(c&255))
+                       b = append(b, byte(c>>8))
+                       if c>>16 != 0 {
+                               t.Errorf("bad test: stringW can't handle >16 bit runes")
+                       }
+               }
+               r := runtime.GostringW(b)
+               if r != s {
+                       t.Errorf("gostringW(%v) = %s, want %s", b, r, s)
+               }
+       }
+}
index bd493d44ae07817dcfcecdeb2a22ffee387753dc..1cdc0fabea91e4762504cf711801725e1c297d81 100644 (file)
@@ -64,3 +64,9 @@ func rawruneslice(size intgo) (b Slice) {
        b.len = size;
        b.cap = mem/sizeof(int32);
 }
+
+// entry point for testing
+// TODO: mcall and run on M stack
+func gostringW(str Slice) (s String) {
+       s = runtime·gostringw((uint16*)str.array);
+}