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