string.goc 5.74 KB
Newer Older
1 2 3 4
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

Russ Cox's avatar
Russ Cox committed
5
package runtime
6
#include "runtime.h"
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
7
#include "arch.h"
8
#include "malloc.h"
9

10
String	runtime·emptystring;
11 12

int32
13
runtime·findnull(byte *s)
14 15 16
{
	int32 l;

Russ Cox's avatar
Russ Cox committed
17 18
	if(s == nil)
		return 0;
19 20 21 22 23
	for(l=0; s[l]!=0; l++)
		;
	return l;
}

24 25 26 27 28 29 30 31 32 33 34 35
int32
runtime·findnullw(uint16 *s)
{
	int32 l;

	if(s == nil)
		return 0;
	for(l=0; s[l]!=0; l++)
		;
	return l;
}

36
uint32 runtime·maxstring = 256;
37

Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
38 39
static String
gostringsize(int32 l)
40
{
41
	String s;
42
	uint32 ms;
43

44
	if(l == 0)
45
		return runtime·emptystring;
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
46 47
	// leave room for NUL for C runtime (e.g., callers of getenv)
	s.str = runtime·mallocgc(l+1, FlagNoPointers, 1, 0);
48
	s.len = l;
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
49
	s.str[l] = 0;
50 51 52 53 54
	for(;;) {
		ms = runtime·maxstring;
		if((uint32)l <= ms || runtime·cas(&runtime·maxstring, ms, (uint32)l))
			break;
	}
55 56 57
	return s;
}

58
String
59
runtime·gostring(byte *str)
Russ Cox's avatar
Russ Cox committed
60 61
{
	int32 l;
62
	String s;
Russ Cox's avatar
Russ Cox committed
63

64
	l = runtime·findnull(str);
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
65
	s = gostringsize(l);
66
	runtime·memmove(s.str, str, l);
Russ Cox's avatar
Russ Cox committed
67 68 69
	return s;
}

Eric Clark's avatar
Eric Clark committed
70
String
71
runtime·gostringn(byte *str, int32 l)
Eric Clark's avatar
Eric Clark committed
72
{
73
	String s;
Eric Clark's avatar
Eric Clark committed
74

Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
75
	s = gostringsize(l);
76
	runtime·memmove(s.str, str, l);
77
	return s;
Eric Clark's avatar
Eric Clark committed
78 79
}

Russ Cox's avatar
Russ Cox committed
80 81 82 83 84 85
Slice
runtime·gobytes(byte *p, int32 n)
{
	Slice sl;

	sl.array = runtime·mallocgc(n, FlagNoPointers, 1, 0);
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
86 87
	sl.len = n;
	sl.cap = n;
Russ Cox's avatar
Russ Cox committed
88 89 90 91
	runtime·memmove(sl.array, p, n);
	return sl;
}

92
String
93
runtime·gostringnocopy(byte *str)
94 95 96 97
{
	String s;
	
	s.str = str;
98
	s.len = runtime·findnull(str);
99 100 101
	return s;
}

102 103 104
String
runtime·gostringw(uint16 *str)
{
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
105
	int32 n1, n2, i;
106 107 108
	byte buf[8];
	String s;

Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
109
	n1 = 0;
110
	for(i=0; str[i]; i++)
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
111 112 113 114 115 116 117 118 119 120 121
		n1 += runtime·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]);
	}
	s.len = n2;
	s.str[s.len] = 0;
122 123 124
	return s;
}

125
String
126
runtime·catstring(String s1, String s2)
127 128 129 130 131 132 133
{
	String s3;

	if(s1.len == 0)
		return s2;
	if(s2.len == 0)
		return s1;
134

Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
135
	s3 = gostringsize(s1.len + s2.len);
136 137
	runtime·memmove(s3.str, s1.str, s1.len);
	runtime·memmove(s3.str+s1.len, s2.str, s2.len);
138
	return s3;
139 140
}

141
static String
142 143 144 145 146 147 148 149
concatstring(int32 n, String *s)
{
	int32 i, l;
	String out;

	l = 0;
	for(i=0; i<n; i++) {
		if(l + s[i].len < l)
150
			runtime·throw("string concatenation too long");
151 152 153
		l += s[i].len;
	}
	
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
154
	out = gostringsize(l);
155 156
	l = 0;
	for(i=0; i<n; i++) {
157
		runtime·memmove(out.str+l, s[i].str, s[i].len);
158 159 160 161
		l += s[i].len;
	}
	return out;
}
162

163 164 165 166 167
#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);
168 169
}

170
static int32
171
cmpstring(String s1, String s2)
172 173 174 175
{
	uint32 i, l;
	byte c1, c2;

176 177 178
	l = s1.len;
	if(s2.len < l)
		l = s2.len;
179
	for(i=0; i<l; i++) {
180 181
		c1 = s1.str[i];
		c2 = s2.str[i];
182 183 184 185 186
		if(c1 < c2)
			return -1;
		if(c1 > c2)
			return +1;
	}
187
	if(s1.len < s2.len)
188
		return -1;
189
	if(s1.len > s2.len)
190 191 192 193
		return +1;
	return 0;
}

Russ Cox's avatar
Russ Cox committed
194
func cmpstring(s1 String, s2 String) (v int32) {
195 196 197 198
	v = cmpstring(s1, s2);
}

int32
199
runtime·strcmp(byte *s1, byte *s2)
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
{
	uint32 i;
	byte c1, c2;

	for(i=0;; i++) {
		c1 = s1[i];
		c2 = s2[i];
		if(c1 < c2)
			return -1;
		if(c1 > c2)
			return +1;
		if(c1 == 0)
			return 0;
	}
}

Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
byte*
runtime·strstr(byte *s1, byte *s2)
{
	byte *sp1, *sp2;

	if(*s2 == 0)
		return s1;
	for(; *s1; s1++) {
		if(*s1 != *s2)
			continue;
		sp1 = s1;
		sp2 = s2;
		for(;;) {
			if(*sp2 == 0)
				return s1;
			if(*sp1++ != *sp2++)
				break;
		}
	}
	return nil;
}

Russ Cox's avatar
Russ Cox committed
238
func slicestring(si String, lindex int32, hindex int32) (so String) {
239 240
	int32 l;

241 242
	if(lindex < 0 || lindex > si.len ||
	   hindex < lindex || hindex > si.len) {
243
	   	runtime·panicslice();
244 245 246
	}

	l = hindex-lindex;
247 248
	so.str = si.str + lindex;
	so.len = l;
249 250
}

Russ Cox's avatar
Russ Cox committed
251 252 253 254
func slicestring1(si String, lindex int32) (so String) {
	int32 l;

	if(lindex < 0 || lindex > si.len) {
255
		runtime·panicslice();
Russ Cox's avatar
Russ Cox committed
256 257 258 259 260
	}

	l = si.len-lindex;
	so.str = si.str + lindex;
	so.len = l;
261 262
}

Russ Cox's avatar
Russ Cox committed
263
func intstring(v int64) (s String) {
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
264
	s = gostringsize(8);
265
	s.len = runtime·runetochar(s.str, v);
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
266
	s.str[s.len] = 0;
267 268
}

269
func slicebytetostring(b Slice) (s String) {
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
270
	s = gostringsize(b.len);
271
	runtime·memmove(s.str, b.array, s.len);
272
}
Ken Thompson's avatar
Ken Thompson committed
273

274
func stringtoslicebyte(s String) (b Slice) {
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
275
	b.array = runtime·mallocgc(s.len, FlagNoPointers, 1, 0);
276 277
	b.len = s.len;
	b.cap = s.len;
278
	runtime·memmove(b.array, s.str, s.len);
279
}
Russ Cox's avatar
Russ Cox committed
280

281
func sliceinttostring(b Slice) (s String) {
282
	int32 siz1, siz2, i;
Ken Thompson's avatar
Ken Thompson committed
283 284 285 286
	int32 *a;
	byte dum[8];

	a = (int32*)b.array;
287
	siz1 = 0;
288
	for(i=0; i<b.len; i++) {
289
		siz1 += runtime·runetochar(dum, a[i]);
Ken Thompson's avatar
Ken Thompson committed
290 291
	}

Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
292
	s = gostringsize(siz1+4);
293
	siz2 = 0;
294
	for(i=0; i<b.len; i++) {
295 296 297
		// check for race
		if(siz2 >= siz1)
			break;
298
		siz2 += runtime·runetochar(s.str+siz2, a[i]);
Ken Thompson's avatar
Ken Thompson committed
299
	}
300
	s.len = siz2;
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
301
	s.str[s.len] = 0;
Ken Thompson's avatar
Ken Thompson committed
302 303
}

304 305 306 307 308 309 310 311 312 313 314
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) {
315
		p += runtime·charntorune(&dum, p, ep-p);
316 317 318
		n++;
	}

Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
319
	b.array = runtime·mallocgc(n*sizeof(r[0]), FlagNoPointers, 1, 0);
320 321 322 323 324
	b.len = n;
	b.cap = n;
	p = s.str;
	r = (int32*)b.array;
	while(p < ep)
325
		p += runtime·charntorune(r++, p, ep-p);
326 327
}

Ken Thompson's avatar
Ken Thompson committed
328 329 330 331 332
enum
{
	Runeself	= 0x80,
};

Russ Cox's avatar
Russ Cox committed
333
func stringiter(s String, k int32) (retk int32) {
Ken Thompson's avatar
tweak  
Ken Thompson committed
334
	int32 l;
Ken Thompson's avatar
Ken Thompson committed
335 336 337 338 339 340 341 342

	if(k >= s.len) {
		// retk=0 is end of iteration
		retk = 0;
		goto out;
	}

	l = s.str[k];
Ken Thompson's avatar
tweak  
Ken Thompson committed
343 344 345
	if(l < Runeself) {
		retk = k+1;
		goto out;
Ken Thompson's avatar
Ken Thompson committed
346 347
	}

Ken Thompson's avatar
tweak  
Ken Thompson committed
348
	// multi-char rune
349
	retk = k + runtime·charntorune(&l, s.str+k, s.len-k);
Ken Thompson's avatar
Ken Thompson committed
350 351 352 353

out:
}

Russ Cox's avatar
Russ Cox committed
354
func stringiter2(s String, k int32) (retk int32, retv int32) {
Ken Thompson's avatar
Ken Thompson committed
355 356 357 358 359 360 361
	if(k >= s.len) {
		// retk=0 is end of iteration
		retk = 0;
		retv = 0;
		goto out;
	}

Ken Thompson's avatar
tweak  
Ken Thompson committed
362 363 364 365
	retv = s.str[k];
	if(retv < Runeself) {
		retk = k+1;
		goto out;
Ken Thompson's avatar
Ken Thompson committed
366 367
	}

Ken Thompson's avatar
tweak  
Ken Thompson committed
368
	// multi-char rune
369
	retk = k + runtime·charntorune(&retv, s.str+k, s.len-k);
Ken Thompson's avatar
Ken Thompson committed
370 371 372

out:
}