source: webkit/trunk/JavaScriptCore/kjs/ustring.cpp@ 1791

Last change on this file since 1791 was 1791, checked in by darin, 23 years ago

JavaScriptCore:

Some string speedups. Makes sony.com cached 11% faster.

  • kjs/ustring.h: Made it possible for UChar objects to be uninitialized, which gives a speed boost. Inlined CString's +=, UString's destructor, +=, and +.
  • kjs/ustring.cpp: (UString::UString): Optimize const char * version, which showed up heavily in performance analysis. Added new two-UString version, which makes the + operator fast. (UString::ascii): Remove thread safety changes. Change static buffer to remember its size, and to always be at least 4096 bytes long; that way we never have to reallocate unless it's for a long string. Also make code to extract the characters significantly faster by getting rid of two pointer dereferences per character. (UString::is8Bit): Avoid one pointer dereference per character. (UString::toDouble): Use ascii() instead of cstring() to avoid copying the string.
  • kjs/collector.cpp: Remove unneeded APPLE_CHANGES.
  • kjs/regexp.cpp: Remove ifdefs around some APPLE_CHANGES that we want to keep, because they just fix warnings.
  • kjs/value.h: Remove obsolete APPLE_CHANGES comment.
  • JavaScriptCore.pbproj/project.pbxproj: Project Builder decided to move a line around in the file.

WebCore:

  • force-clean-timestamp: JavaScriptCore headers changed that require a full build here.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2000 Harri Porten ([email protected])
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 *
21 */
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#include <stdlib.h>
28#include <stdio.h>
29#include <ctype.h>
30#ifdef HAVE_STRING_H
31#include <string.h>
32#endif
33#ifdef HAVE_STRINGS_H
34#include <strings.h>
35#endif
36
37#include "ustring.h"
38#include "operations.h"
39#include <math.h>
40
41namespace KJS {
42 extern const double NaN;
43 extern const double Inf;
44};
45
46using namespace KJS;
47
48CString::CString(const char *c)
49{
50 data = new char[strlen(c)+1];
51 strcpy(data, c);
52}
53
54CString::CString(const CString &b)
55{
56 data = new char[b.size()+1];
57 strcpy(data, b.c_str());
58}
59
60CString::~CString()
61{
62 delete [] data;
63}
64
65CString &CString::append(const CString &t)
66{
67 char *n;
68 if (data) {
69 n = new char[strlen(data)+t.size()+1];
70 strcpy(n, data);
71 } else {
72 n = new char[t.size()+1];
73 n[0] = '\0';
74 }
75 strcat(n, t.c_str());
76
77 delete [] data;
78 data = n;
79
80 return *this;
81}
82
83CString &CString::operator=(const char *c)
84{
85 if (data)
86 delete [] data;
87 data = new char[strlen(c)+1];
88 strcpy(data, c);
89
90 return *this;
91}
92
93CString &CString::operator=(const CString &str)
94{
95 if (this == &str)
96 return *this;
97
98 if (data)
99 delete [] data;
100 data = new char[str.size()+1];
101 strcpy(data, str.c_str());
102
103 return *this;
104}
105
106int CString::size() const
107{
108 return strlen(data);
109}
110
111bool KJS::operator==(const KJS::CString& c1, const KJS::CString& c2)
112{
113 return (strcmp(c1.c_str(), c2.c_str()) == 0);
114}
115
116UChar UChar::null;
117UString::Rep UString::Rep::null = { 0, 0, 0, 1 };
118UString UString::null;
119const int normalStatBufferSize = 4096;
120static char *statBuffer = 0;
121static int statBufferSize = 0;
122
123UChar::UChar(const UCharReference &c)
124 : uc( c.unicode() )
125{
126}
127
128UChar UChar::toLower() const
129{
130 // ### properly support unicode tolower
131 if (uc >= 256 || islower(uc))
132 return *this;
133
134 return (unsigned char)tolower(uc);
135}
136
137UChar UChar::toUpper() const
138{
139 if (uc >= 256 || isupper(uc))
140 return *this;
141
142 return (unsigned char)toupper(uc);
143}
144
145UCharReference& UCharReference::operator=(UChar c)
146{
147 str->detach();
148 if (offset < str->rep->len)
149 *(str->rep->dat + offset) = c;
150 /* TODO: lengthen string ? */
151 return *this;
152}
153
154UChar& UCharReference::ref() const
155{
156 if (offset < str->rep->len)
157 return *(str->rep->dat + offset);
158 else
159 return UChar::null;
160}
161
162UString::Rep *UString::Rep::create(UChar *d, int l)
163{
164 Rep *r = new Rep;
165 r->dat = d;
166 r->len = l;
167 r->capacity = l;
168 r->rc = 1;
169
170 return r;
171}
172
173UString::UString()
174{
175 null.rep = &Rep::null;
176 attach(&Rep::null);
177}
178
179UString::UString(char c)
180{
181 UChar *d = new UChar[1];
182 d[0] = c;
183 rep = Rep::create(d, 1);
184}
185
186UString::UString(const char *c)
187{
188 if (!c) {
189 attach(&Rep::null);
190 return;
191 }
192 int length = strlen(c);
193 UChar *d = new UChar[length];
194 for (int i = 0; i < length; i++)
195 d[i].uc = c[i];
196 rep = Rep::create(d, length);
197}
198
199UString::UString(const UChar *c, int length)
200{
201 UChar *d = new UChar[length];
202 memcpy(d, c, length * sizeof(UChar));
203 rep = Rep::create(d, length);
204}
205
206UString::UString(UChar *c, int length, bool copy)
207{
208 UChar *d;
209 if (copy) {
210 d = new UChar[length];
211 memcpy(d, c, length * sizeof(UChar));
212 } else
213 d = c;
214 rep = Rep::create(d, length);
215}
216
217UString::UString(const UString &b)
218{
219 attach(b.rep);
220}
221
222UString::UString(const UString &a, const UString &b)
223{
224 int aSize = a.size();
225 int bSize = b.size();
226 UChar *d = new UChar[aSize + bSize];
227 memcpy(d, a.data(), aSize * sizeof(UChar));
228 memcpy(d + aSize, b.data(), bSize * sizeof(UChar));
229 rep = Rep::create(d, aSize + bSize);
230}
231
232UString UString::from(int i)
233{
234 char buf[40];
235 sprintf(buf, "%d", i);
236
237 return UString(buf);
238}
239
240UString UString::from(unsigned int u)
241{
242 char buf[40];
243 sprintf(buf, "%u", u);
244
245 return UString(buf);
246}
247
248UString UString::from(double d)
249{
250 char buf[40];
251
252 if (d == -0)
253 strcpy(buf,"0");
254 else if (KJS::isNaN(d))
255 strcpy(buf,"NaN");
256 else if (KJS::isPosInf(d))
257 strcpy(buf,"Infinity");
258 else if (KJS::isNegInf(d))
259 strcpy(buf,"-Infinity");
260 else
261 sprintf(buf, "%.16g", d); // does the right thing
262
263 // ECMA 3rd ed. 9.8.1 9 e: "with no leading zeros"
264 int buflen = strlen(buf);
265 if (buflen >= 4 && buf[buflen-4] == 'e' && buf[buflen-2] == '0') {
266 buf[buflen-2] = buf[buflen-1];
267 buf[buflen-1] = 0;
268 }
269
270 return UString(buf);
271}
272
273UString &UString::append(const UString &t)
274{
275 int l = size();
276 int tLen = t.size();
277 int newLen = l + tLen;
278 if (rep->rc == 1 && newLen <= rep->capacity) {
279 memcpy(rep->dat+l, t.data(), tLen * sizeof(UChar));
280 rep->len = newLen;
281 return *this;
282 }
283
284 int newCapacity = (newLen * 3 + 1) / 2;
285 UChar *n = new UChar[newCapacity];
286 memcpy(n, data(), l * sizeof(UChar));
287 memcpy(n+l, t.data(), tLen * sizeof(UChar));
288 release();
289 rep = Rep::create(n, newLen);
290 rep->capacity = newCapacity;
291
292 return *this;
293}
294
295CString UString::cstring() const
296{
297 return ascii();
298}
299
300char *UString::ascii() const
301{
302 // Never make the buffer smaller than normalStatBufferSize.
303 // Thus we almost never need to reallocate.
304 int length = size();
305 int neededSize = length + 1;
306 if (neededSize < normalStatBufferSize) {
307 neededSize = normalStatBufferSize;
308 }
309 if (neededSize != statBufferSize) {
310 delete [] statBuffer;
311 statBuffer = new char [neededSize];
312 statBufferSize = neededSize;
313 }
314
315 const UChar *p = data();
316 char *q = statBuffer;
317 const UChar *limit = p + length;
318 while (p != limit) {
319 *q = p->uc;
320 ++p;
321 ++q;
322 }
323 *q = '\0';
324
325 return statBuffer;
326}
327
328#ifdef KJS_DEBUG_MEM
329void UString::globalClear()
330{
331 delete [] statBuffer;
332 statBuffer = 0;
333 statBufferSize = 0;
334}
335#endif
336
337UString &UString::operator=(const char *c)
338{
339 int l = c ? strlen(c) : 0;
340 UChar *d;
341 if (rep->rc == 1 && l < rep->capacity) {
342 d = rep->dat;
343 } else {
344 release();
345 d = new UChar[l];
346 rep = Rep::create(d, l);
347 }
348 for (int i = 0; i < l; i++)
349 d[i].uc = c[i];
350
351 return *this;
352}
353
354UString &UString::operator=(const UString &str)
355{
356 str.rep->ref();
357 release();
358 rep = str.rep;
359
360 return *this;
361}
362
363bool UString::is8Bit() const
364{
365 const UChar *u = data();
366 const UChar *limit = u + size();
367 while (u < limit) {
368 if (u->uc > 0xFF)
369 return false;
370 ++u;
371 }
372
373 return true;
374}
375
376UChar UString::operator[](int pos) const
377{
378 if (pos >= size())
379 return UChar::null;
380
381 return ((UChar *)data())[pos];
382}
383
384UCharReference UString::operator[](int pos)
385{
386 /* TODO: boundary check */
387 return UCharReference(this, pos);
388}
389
390double UString::toDouble( bool tolerant ) const
391{
392 double d;
393
394 if (!is8Bit())
395 return NaN;
396
397 const char *c = ascii();
398
399 // skip leading white space
400 while (isspace(*c))
401 c++;
402
403 // empty string ?
404 if (*c == '\0')
405 return tolerant ? NaN : 0.0;
406
407 // hex number ?
408 if (*c == '0' && (*(c+1) == 'x' || *(c+1) == 'X')) {
409 c++;
410 d = 0.0;
411 while (*(++c)) {
412 if (*c >= '0' && *c <= '9')
413 d = d * 16.0 + *c - '0';
414 else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f'))
415 d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0;
416 else
417 break;
418 }
419 } else {
420 // regular number ?
421 char *end;
422 d = strtod(c, &end);
423 if ((d != 0.0 || end != c) && d != HUGE_VAL && d != -HUGE_VAL) {
424 c = end;
425 } else {
426 // infinity ?
427 d = 1.0;
428 if (*c == '+')
429 c++;
430 else if (*c == '-') {
431 d = -1.0;
432 c++;
433 }
434 if (strncmp(c, "Infinity", 8) != 0)
435 return NaN;
436 d = d * Inf;
437 c += 8;
438 }
439 }
440
441 // allow trailing white space
442 while (isspace(*c))
443 c++;
444 // don't allow anything after - unless tolerant=true
445 if ( !tolerant && *c != '\0')
446 d = NaN;
447
448 return d;
449}
450
451unsigned long UString::toULong(bool *ok) const
452{
453 double d = toDouble();
454 bool b = true;
455
456 if (isNaN(d) || d != static_cast<unsigned long>(d)) {
457 b = false;
458 d = 0;
459 }
460
461 if (ok)
462 *ok = b;
463
464 return static_cast<unsigned long>(d);
465}
466
467int UString::find(const UString &f, int pos) const
468{
469 if (isNull())
470 return -1;
471 long fsize = f.size() * sizeof(UChar);
472 if (pos < 0)
473 pos = 0;
474 const UChar *end = data() + size() - f.size();
475 for (const UChar *c = data() + pos; c <= end; c++)
476 if (!memcmp((void*)c, (void*)f.data(), fsize))
477 return (c-data());
478
479 return -1;
480}
481
482int UString::rfind(const UString &f, int pos) const
483{
484 if (isNull())
485 return -1;
486 if (pos + f.size() >= size())
487 pos = size() - f.size();
488 long fsize = f.size() * sizeof(UChar);
489 for (const UChar *c = data() + pos; c >= data(); c--) {
490 if (!memcmp((void*)c, (void*)f.data(), fsize))
491 return (c-data());
492 }
493
494 return -1;
495}
496
497UString UString::substr(int pos, int len) const
498{
499 if (isNull())
500 return UString();
501 if (pos < 0)
502 pos = 0;
503 else if (pos >= (int) size())
504 pos = size();
505 if (len < 0)
506 len = size();
507 if (pos + len >= (int) size())
508 len = size() - pos;
509
510 UChar *tmp = new UChar[len];
511 memcpy(tmp, data()+pos, len * sizeof(UChar));
512 UString result(tmp, len);
513 delete [] tmp;
514
515 return result;
516}
517
518void UString::attach(Rep *r)
519{
520 rep = r;
521 rep->ref();
522}
523
524void UString::detach()
525{
526 if (rep->rc > 1) {
527 int l = size();
528 UChar *n = new UChar[l];
529 memcpy(n, data(), l * sizeof(UChar));
530 release();
531 rep = Rep::create(n, l);
532 }
533}
534
535void UString::release()
536{
537 if (!rep->deref()) {
538 delete [] rep->dat;
539 delete rep;
540 }
541}
542
543bool KJS::operator==(const UString& s1, const UString& s2)
544{
545 if (s1.rep->len != s2.rep->len)
546 return false;
547
548 return (memcmp(s1.rep->dat, s2.rep->dat,
549 s1.rep->len * sizeof(UChar)) == 0);
550}
551
552bool KJS::operator==(const UString& s1, const char *s2)
553{
554 if (s2 == 0L && s1.isNull())
555 return true;
556
557 if (s1.size() != (int) strlen(s2))
558 return false;
559
560 const UChar *u = s1.data();
561 while (*s2) {
562 if (u->uc != *s2 )
563 return false;
564 s2++;
565 u++;
566 }
567
568 return true;
569}
570
571bool KJS::operator<(const UString& s1, const UString& s2)
572{
573 const int l1 = s1.size();
574 const int l2 = s2.size();
575 const int lmin = l1 < l2 ? l1 : l2;
576 const UChar *c1 = s1.data();
577 const UChar *c2 = s2.data();
578 int l = 0;
579 while (l < lmin && *c1 == *c2) {
580 c1++;
581 c2++;
582 l++;
583 }
584 if (l < lmin)
585 return (c1->unicode() < c2->unicode());
586
587 return (l1 < l2);
588}
Note: See TracBrowser for help on using the repository browser.