1 #include "Core.h"
2 
3 namespace Upp {
4 
5 #ifdef _DEBUG
Dsyn()6 void String0::Dsyn()
7 {
8 	String *d_str = static_cast<String *>(this);
9 	d_str->s = Begin();
10 	d_str->len = GetCount();
11 }
12 #endif
13 
14 String0::Rc String0::voidptr[2];
15 
LSet(const String0 & s)16 void String0::LSet(const String0& s)
17 {
18 	w[2] = s.w[2];
19 	w[3] = s.w[3];
20 	if(s.IsRef()) {
21 		ptr = s.ptr;
22 		if(ptr != (char *)(voidptr + 1))
23 			AtomicInc(s.Ref()->refcount);
24 	}
25 	else {
26 		ptr = (char *)MemoryAlloc32();
27 		qword *d = qptr;
28 		const qword *q = s.qptr;
29 		d[0] = q[0];
30 		d[1] = q[1];
31 		d[2] = q[2];
32 		d[3] = q[3];
33 	}
34 }
35 
LFree()36 void String0::LFree()
37 {
38 	if(IsRef()) {
39 		if(ptr != (char *)(voidptr + 1)) {
40 			Rc *rc = Ref();
41 			ASSERT(rc->refcount > 0);
42 			if(AtomicDec(rc->refcount) == 0) MemoryFree(rc);
43 		}
44 	}
45 	else
46 		MemoryFree32(ptr);
47 }
48 
LEq(const String0 & s) const49 bool String0::LEq(const String0& s) const
50 {
51 	int l = GetCount();
52 	return l == s.GetCount() && inline_memeq8_aligned(begin(), s.begin(), l);
53 }
54 
LHashValue() const55 hash_t String0::LHashValue() const
56 {
57 	int l = LLen();
58 	if(l < 15) { // must be the same as small hash
59 #ifdef HASH64
60 		qword m[2];
61 		m[0] = m[1] = 0;
62 		memcpy8((char *)m, ptr, l);
63 		((byte *)m)[SLEN] = l;
64 		return CombineHash(m[0], m[1]);
65 #else
66 		dword m[4];
67 		m[0] = m[1] = m[2] = m[3] = 0;
68 		memcpy8((char *)m, ptr, l);
69 		((byte *)m)[SLEN] = l;
70 		return CombineHash(m[0], m[1], m[2], m[3]);
71 #endif
72 	}
73 	return memhash(ptr, l);
74 }
75 
Compare(const String0 & s) const76 int String0::Compare(const String0& s) const
77 {
78 	const char *a = Begin();
79 	int la = GetLength();
80 	const char *b = s.Begin();
81 	int lb = s.GetLength();
82 	int q = inline_memcmp_aligned(a, b, min(la, lb));
83 	return q ? q : SgnCompare(la, lb);
84 }
85 
Alloc(int count,char & kind)86 char *String0::Alloc(int count, char& kind)
87 {
88 	if(count < 32) {
89 		kind = MEDIUM;
90 		return (char *)MemoryAlloc32();
91 	}
92 	size_t sz = sizeof(Rc) + count + 1;
93 	Rc *rc = (Rc *)MemoryAllocSz(sz);
94 	rc->alloc = count == INT_MAX ? INT_MAX : (int)sz - sizeof(Rc) - 1;
95 	rc->refcount = 1;
96 	kind = min(rc->alloc, 255);
97 	return rc->GetPtr();
98 }
99 
Insert(int pos,int count,const char * s)100 char *String0::Insert(int pos, int count, const char *s)
101 {
102 	ASSERT(pos >= 0 && count >= 0 && pos <= GetCount());
103 	int len = GetCount();
104 	int newlen = len + count;
105 	if(newlen < len) // overflow, string >2GB
106 		Panic("String is too big!");
107 	char *str = (char *)Begin();
108 	if(newlen < GetAlloc() && !IsSharedRef() && (!s || s < str || s > str + len)) {
109 		if(pos < len)
110 			memmove(str + pos + count, str + pos, len - pos);
111 		if(IsSmall())
112 			SLen() = newlen;
113 		else
114 			LLen() = newlen;
115 		str[newlen] = 0;
116 		if(s)
117 			memcpy8(str + pos, s, count);
118 		Dsyn();
119 		return str + pos;
120 	}
121 	char kind;
122 	char *p = Alloc(max(len >= int((int64)2 * INT_MAX / 3) ? INT_MAX : len + (len >> 1), newlen),
123 	                kind);
124 	if(pos > 0)
125 		memcpy8(p, str, pos);
126 	if(pos < len)
127 		memcpy8(p + pos + count, str + pos, len - pos);
128 	if(s)
129 		memcpy8(p + pos, s, count);
130 	p[newlen] = 0;
131 	Free();
132 	ptr = p;
133 	LLen() = newlen;
134 	SLen() = 15;
135 	chr[KIND] = kind;
136 	Dsyn();
137 	return ptr + pos;
138 }
139 
UnShare()140 void String0::UnShare()
141 {
142 	if(IsSharedRef()) {
143 		int len = LLen();
144 		char kind;
145 		char *p = Alloc(len, kind);
146 		memcpy8(p, ptr, len + 1);
147 		Free();
148 		chr[KIND] = kind;
149 		ptr = p;
150 	}
151 }
152 
SetSLen(int l)153 void String0::SetSLen(int l)
154 {
155 	SLen() = l;
156 	memset(chr + l, 0, 15 - l);
157 }
158 
Remove(int pos,int count)159 void String0::Remove(int pos, int count)
160 {
161 	ASSERT(pos >= 0 && count >= 0 && pos + count <= GetCount());
162 	UnShare();
163 	char *s = (char *)Begin();
164 	memmove(s + pos, s + pos + count, GetCount() - pos - count + 1);
165 	if(IsSmall())
166 		SetSLen(SLen() - count);
167 	else
168 		LLen() -= count;
169 	Dsyn();
170 }
171 
Set(int pos,int chr)172 void String0::Set(int pos, int chr)
173 {
174 	ASSERT(pos >= 0 && pos < GetCount());
175 	UnShare();
176 	Ptr()[pos] = chr;
177 }
178 
Trim(int pos)179 void String0::Trim(int pos)
180 {
181 	ASSERT(pos >= 0 && pos <= GetCount());
182 	if(IsSmall()) {
183 		chr[pos] = 0;
184 		SetSLen(pos);
185 	}
186 	else {
187 		UnShare();
188 		ptr[pos] = 0;
189 		LLen() = pos;
190 	}
191 	Dsyn();
192 }
193 
LCat(int c)194 void String0::LCat(int c)
195 {
196 	if(IsSmall()) {
197 		qword *x = (qword *)MemoryAlloc32();
198 		x[0] = q[0];
199 		x[1] = q[1];
200 		LLen() = SLen();
201 		SLen() = 15;
202 		chr[KIND] = MEDIUM;
203 		qptr = x;
204 	}
205 	int l = LLen();
206 	if(IsRef() ? !IsShared() && l < (int)Ref()->alloc : l < 31) {
207 		ptr[l] = c;
208 		ptr[LLen() = l + 1] = 0;
209 	}
210 	else {
211 		char *s = Insert(l, 1, NULL);
212 		s[0] = c;
213 		s[1] = 0;
214 	}
215 }
216 
Cat(const char * s,int len)217 void String0::Cat(const char *s, int len)
218 {
219 	if(IsSmall()) {
220 		if(SLen() + len < 14) {
221 			memcpy8(chr + SLen(), s, len);
222 			SLen() += len;
223 			chr[(int)SLen()] = 0;
224 			Dsyn();
225 			return;
226 		}
227 	}
228 	else
229 		if((int)LLen() + len < LAlloc() && !IsSharedRef()) {
230 			memcpy8(ptr + LLen(), s, len);
231 			LLen() += len;
232 			ptr[LLen()] = 0;
233 			Dsyn();
234 			return;
235 		}
236 	Insert(GetCount(), len, s);
237 }
238 
Reserve(int r)239 void String0::Reserve(int r)
240 {
241 	int l = GetCount();
242 	Insert(GetCount(), r, NULL);
243 	Trim(l);
244 }
245 
SetL(const char * s,int len)246 void String0::SetL(const char *s, int len)
247 {
248 	char *p = Alloc(len, chr[KIND]);
249 	memcpy8(p, s, len);
250 	p[len] = 0;
251 	ptr = p;
252 	LLen() = len;
253 	SLen() = 15;
254 }
255 
Set0(const char * s,int len)256 void String0::Set0(const char *s, int len)
257 {
258 	Zero();
259 	if(len <= 14) {
260 		SLen() = len;
261 		memcpy8(chr, s, len);
262 	}
263 	else
264 		SetL(s, len);
265 	Dsyn();
266 }
267 
AssignLen(const char * s,int slen)268 void String::AssignLen(const char *s, int slen)
269 {
270 	int  len = GetCount();
271 	char *str = (char *)Begin();
272 	if(s >= str && s <= str + len)
273 		*this = String(s, slen);
274 	else {
275 		String0::Free();
276 		String0::Set0(s, slen);
277 	}
278 }
279 
GetVoid()280 String String::GetVoid()
281 {
282 	String s;
283 	s.ptr = (char *)(voidptr + 1);
284 	s.LLen() = 0;
285 	s.SLen() = 15;
286 	s.chr[KIND] = 50;
287 	return s;
288 }
289 
IsVoid() const290 bool String::IsVoid() const
291 {
292 	return IsRef() && ptr == (char *)(voidptr + 1);
293 }
294 
ToWString() const295 WString String::ToWString() const
296 {
297 	return WString(Begin(), GetCount());
298 }
299 
GetCharCount() const300 int String::GetCharCount() const
301 {
302 	return GetDefaultCharset() == CHARSET_UTF8 ?  utf8len(Begin(), GetCount()) : GetCount();
303 }
304 
String(StringBuffer & b)305 String::String(StringBuffer& b)
306 {
307 	Zero();
308 	if(b.pbegin == b.buffer) {
309 		String0::Set0(b.pbegin, (int)(uintptr_t)(b.pend - b.pbegin));
310 		return;
311 	}
312 	int l = b.GetLength();
313 	if(l <= 14) {
314 		memcpy8(chr, b.pbegin, l);
315 		SLen() = l;
316 		b.Free();
317 	}
318 	else {
319 		ptr = b.pbegin;
320 		ptr[l] = 0;
321 		SLen() = 15;
322 		LLen() = l;
323 		chr[KIND] = min(b.GetAlloc(), 255);
324 		if(GetAlloc() > 4 * GetLength() / 3)
325 			Shrink();
326 	}
327 	b.Zero();
328 
329 //	char h[100];
330 //	DLOG(sprintf(h, "String(StringBuffer) end %p (%p)", ptr, this));
331 	Dsyn();
332 //	DLOG(sprintf(h, "String(StringBuffer) end2 %p (%p)", ptr, this));
333 }
334 
Alloc(int count,int & alloc)335 char *StringBuffer::Alloc(int count, int& alloc)
336 {
337 	if(count <= 31) {
338 		char *s = (char *)MemoryAlloc32();
339 		alloc = 31;
340 		return s;
341 	}
342 	else {
343 		size_t sz = sizeof(Rc) + count + 1;
344 		Rc *rc = (Rc *)MemoryAlloc(sz);
345 		alloc = rc->alloc = (int)min((size_t)INT_MAX, sz - sizeof(Rc) - 1);
346 		rc->refcount = 1;
347 		return (char *)(rc + 1);
348 	}
349 }
350 
Free()351 void StringBuffer::Free()
352 {
353 	if(pbegin == buffer)
354 		return;
355 	int all = (int)(limit - pbegin);
356 	if(all == 31)
357 		MemoryFree32(pbegin);
358 	if(all > 31)
359 		MemoryFree((Rc *)pbegin - 1);
360 }
361 
Realloc(dword n,const char * cat,int l)362 void StringBuffer::Realloc(dword n, const char *cat, int l)
363 {
364 	int al;
365 	size_t ep = pend - pbegin;
366 	if(n > INT_MAX)
367 		n = INT_MAX;
368 	bool realloced = false;
369 	char *p;
370 	if((int)(limit - pbegin) > 800) {
371 		size_t sz = sizeof(Rc) + n + 1;
372 		Rc *rc = (Rc *)pbegin - 1;
373 		if(MemoryTryRealloc(rc, sz)) {
374 			realloced = true;
375 			al = rc->alloc = (int)min((size_t)INT_MAX, sz - sizeof(Rc) - 1);
376 			p = pbegin;
377 		}
378 	}
379 	if(!realloced) {
380 		p = Alloc(n, al);
381 		memcpy8(p, pbegin, min((dword)GetLength(), n));
382 	}
383 	if(cat) {
384 		if(ep + l > INT_MAX)
385 			Panic("StringBuffer is too big (>2GB)!");
386 		memcpy8(p + ep, cat, l);
387 		ep += l;
388 	}
389 	if(!realloced) {
390 		Free();
391 		pbegin = p;
392 	}
393 	pend = pbegin + ep;
394 	limit = pbegin + al;
395 }
396 
Expand()397 void StringBuffer::Expand()
398 {
399 	Realloc(GetLength() * 3 / 2);
400 	if(pend == limit)
401 		Panic("StringBuffer is too big!");
402 }
403 
SetLength(int l)404 void StringBuffer::SetLength(int l)
405 {
406 	if(l > GetAlloc())
407 		Realloc(l);
408 	pend = pbegin + l;
409 }
410 
Shrink()411 void StringBuffer::Shrink()
412 {
413 	int l = GetLength();
414 	if(l < GetAlloc() && l > 14)
415 		Realloc(l);
416 	pend = pbegin + l;
417 }
418 
ReallocL(const char * s,int l)419 void StringBuffer::ReallocL(const char *s, int l)
420 {
421 	Realloc(max(GetLength(), l) + GetLength(), s, l);
422 }
423 
Set(String & s)424 void StringBuffer::Set(String& s)
425 {
426 	s.UnShare();
427 	int l = s.GetLength();
428 	if(s.GetAlloc() == 14) {
429 		pbegin = (char *)MemoryAlloc32();
430 		limit = pbegin + 31;
431 		memcpy8(pbegin, s.Begin(), l);
432 		pend = pbegin + l;
433 	}
434 	else {
435 		pbegin = s.ptr;
436 		pend = pbegin + l;
437 		limit = pbegin + s.GetAlloc();
438 	}
439 	s.Zero();
440 }
441 
TrimLeft(const String & str)442 String TrimLeft(const String& str)
443 {
444 	const char *s = str;
445 	if(!IsSpace(*s))
446 		return str;
447 	while(IsSpace((byte)*s)) s++;
448 	return String(s, str.End());
449 }
450 
TrimRight(const String & str)451 String TrimRight(const String& str)
452 {
453 	if(str.IsEmpty())
454 		return str;
455 	const char *s = str.Last();
456 	if(!IsSpace(*s))
457 		return str;
458 	while(s >= ~str && IsSpace((byte)*s)) s--;
459 	return String(~str, s + 1);
460 }
461 
TrimBoth(const String & str)462 String TrimBoth(const String& str)
463 {
464 	return TrimLeft(TrimRight(str));
465 }
466 
TrimLeft(const char * sw,int len,const String & s)467 String TrimLeft(const char *sw, int len, const String& s)
468 {
469 	return s.StartsWith(sw, len) ? s.Mid(len) : s;
470 }
471 
TrimRight(const char * sw,int len,const String & s)472 String TrimRight(const char *sw, int len, const String& s)
473 {
474 	return s.EndsWith(sw, len) ? s.Mid(0, s.GetCount() - len) : s;
475 }
476 
477 struct StringICompare__
478 {
479 	int encoding;
operator ()Upp::StringICompare__480 	int operator()(char a, char b) const { return ToUpper(a, encoding) - ToUpper(b, encoding); }
481 
StringICompare__Upp::StringICompare__482 	StringICompare__(int e) : encoding(e) {}
483 };
484 
CompareNoCase(const String & a,const String & b,byte encoding)485 int CompareNoCase(const String& a, const String& b, byte encoding)
486 {
487 	if(encoding == CHARSET_DEFAULT) encoding = GetDefaultCharset();
488 	if(encoding == CHARSET_UTF8) return CompareNoCase(FromUtf8(a), FromUtf8(b));
489 #ifdef DEPRECATED
490 	return IterCompare(a.Begin(), a.End(), b.Begin(), b.End(), StringICompare__(encoding));
491 #else
492 	return CompareRanges(a, b, StringICompare__(encoding));
493 #endif
494 }
495 
CompareNoCase(const String & a,const char * b,byte encoding)496 int CompareNoCase(const String& a, const char *b, byte encoding)
497 {
498 	if(encoding == CHARSET_DEFAULT) encoding = GetDefaultCharset();
499 	if(encoding == CHARSET_UTF8) return CompareNoCase(FromUtf8(a), FromUtf8(b, (int)strlen(b)));
500 #ifdef DEPRECATED
501 	return IterCompare(a.Begin(), a.End(), b, b + strlen(b), StringICompare__(encoding));
502 #else
503 	return CompareRanges(a, SubRange(b, b + strlen(b)), StringICompare__(encoding));
504 #endif
505 }
506 
507 }
508