source: webkit/trunk/JavaScriptCore/runtime/UString.h@ 54510

Last change on this file since 54510 was 54464, checked in by [email protected], 15 years ago

Change UStringImpl::create to CRASH if the string cannot be allocated,
rather than returning a null string (which will behave like a zero-length
string if used).

Reviewed by Geoff Garen.

Also move createRep function from UString to become new overloaded
UStringImpl::create methods. In doing so, bring their behaviour closer to
being in line with WebCore::StringImpl, in removing the behaviour that they
can be used to produce null UStrings (ASSERT the char* provided is non-null).
This behaviour of converting null C-strings to null UStrings is inefficient
(cmompared to just using UString::null()), incompatible with WebCore::StringImpl's
behaviour, and may generate unexpected behaviour, since in many cases a null
UString can be used like an empty string.

With these changes UStringImpl need not have a concept of null impls, we can
start transitioning this to become an implementation detail of UString, that
internally it chooses to use a null-object rather than an actually zero impl
pointer.

(JSC::Debugger::recompileAllJSFunctions):

  • debugger/DebuggerCallFrame.cpp:

(JSC::DebuggerCallFrame::calculatedFunctionName):

  • parser/Parser.cpp:

(JSC::Parser::parse):

  • profiler/Profile.cpp:

(JSC::Profile::Profile):

  • profiler/ProfileGenerator.cpp:

(JSC::ProfileGenerator::stopProfiling):

  • runtime/Error.cpp:

(JSC::Error::create):
(JSC::throwError):

  • runtime/ExceptionHelpers.cpp:

(JSC::createError):

  • runtime/Identifier.cpp:

(JSC::Identifier::add):

  • runtime/PropertyNameArray.cpp:

(JSC::PropertyNameArray::add):

  • runtime/UString.cpp:

(JSC::initializeUString):
(JSC::UString::UString):
(JSC::UString::operator=):

  • runtime/UString.h:

(JSC::UString::isNull):
(JSC::UString::null):
(JSC::UString::rep):
(JSC::UString::UString):

  • runtime/UStringImpl.cpp:

(JSC::UStringImpl::create):

  • runtime/UStringImpl.h:
  • Property svn:eol-style set to native
File size: 19.8 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4 * Copyright (C) 2009 Google Inc. All rights reserved.
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., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#ifndef UString_h
24#define UString_h
25
26#include "Collector.h"
27#include "UStringImpl.h"
28#include <stdint.h>
29#include <string.h>
30#include <wtf/Assertions.h>
31#include <wtf/CrossThreadRefCounted.h>
32#include <wtf/OwnFastMallocPtr.h>
33#include <wtf/PassRefPtr.h>
34#include <wtf/PtrAndFlags.h>
35#include <wtf/RefPtr.h>
36#include <wtf/Vector.h>
37#include <wtf/unicode/Unicode.h>
38
39namespace JSC {
40
41 using WTF::PlacementNewAdoptType;
42 using WTF::PlacementNewAdopt;
43
44 class CString {
45 public:
46 CString()
47 : m_length(0)
48 , m_data(0)
49 {
50 }
51
52 CString(const char*);
53 CString(const char*, size_t);
54 CString(const CString&);
55
56 ~CString();
57
58 static CString adopt(char*, size_t); // buffer should be allocated with new[].
59
60 CString& append(const CString&);
61 CString& operator=(const char* c);
62 CString& operator=(const CString&);
63 CString& operator+=(const CString& c) { return append(c); }
64
65 size_t size() const { return m_length; }
66 const char* c_str() const { return m_data; }
67
68 private:
69 size_t m_length;
70 char* m_data;
71 };
72
73 bool operator==(const CString&, const CString&);
74
75 typedef Vector<char, 32> CStringBuffer;
76
77 class UString {
78 friend class JIT;
79
80 public:
81 typedef UStringImpl Rep;
82
83 public:
84 // UString constructors passed char*s assume ISO Latin-1 encoding; for UTF8 use 'createFromUTF8', below.
85 UString();
86 UString(const char*); // Constructor for null-terminated string.
87 UString(const char*, int length);
88 UString(const UChar*, int length);
89 UString(const Vector<UChar>& buffer);
90
91 UString(const UString& s)
92 : m_rep(s.m_rep)
93 {
94 }
95
96 // Special constructor for cases where we overwrite an object in place.
97 UString(PlacementNewAdoptType)
98 : m_rep(PlacementNewAdopt)
99 {
100 }
101
102 ~UString()
103 {
104 }
105
106 template<size_t inlineCapacity>
107 static PassRefPtr<UStringImpl> adopt(Vector<UChar, inlineCapacity>& vector)
108 {
109 return Rep::adopt(vector);
110 }
111
112 static UString createFromUTF8(const char*);
113
114 static UString from(int);
115 static UString from(long long);
116 static UString from(unsigned int);
117 static UString from(long);
118 static UString from(double);
119
120 struct Range {
121 public:
122 Range(int pos, int len)
123 : position(pos)
124 , length(len)
125 {
126 }
127
128 Range()
129 {
130 }
131
132 int position;
133 int length;
134 };
135
136 UString spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const;
137
138 UString replaceRange(int rangeStart, int RangeEnd, const UString& replacement) const;
139
140 bool getCString(CStringBuffer&) const;
141
142 // NOTE: This method should only be used for *debugging* purposes as it
143 // is neither Unicode safe nor free from side effects nor thread-safe.
144 char* ascii() const;
145
146 /**
147 * Convert the string to UTF-8, assuming it is UTF-16 encoded.
148 * In non-strict mode, this function is tolerant of badly formed UTF-16, it
149 * can create UTF-8 strings that are invalid because they have characters in
150 * the range U+D800-U+DDFF, U+FFFE, or U+FFFF, but the UTF-8 string is
151 * guaranteed to be otherwise valid.
152 * In strict mode, error is returned as null CString.
153 */
154 CString UTF8String(bool strict = false) const;
155
156 UString& operator=(const char*c);
157
158 const UChar* data() const { return m_rep->data(); }
159
160 bool isNull() const { return m_rep == s_nullRep; }
161 bool isEmpty() const { return !m_rep->size(); }
162
163 bool is8Bit() const;
164
165 int size() const { return m_rep->size(); }
166
167 UChar operator[](int pos) const;
168
169 double toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const;
170 double toDouble(bool tolerateTrailingJunk) const;
171 double toDouble() const;
172
173 uint32_t toUInt32(bool* ok = 0) const;
174 uint32_t toUInt32(bool* ok, bool tolerateEmptyString) const;
175 uint32_t toStrictUInt32(bool* ok = 0) const;
176
177 unsigned toArrayIndex(bool* ok = 0) const;
178
179 int find(const UString& f, int pos = 0) const;
180 int find(UChar, int pos = 0) const;
181 int rfind(const UString& f, int pos) const;
182 int rfind(UChar, int pos) const;
183
184 UString substr(int pos = 0, int len = -1) const;
185
186 static const UString& null() { return *s_nullUString; }
187
188 Rep* rep() const { return m_rep.get(); }
189
190 UString(PassRefPtr<Rep> r)
191 : m_rep(r)
192 {
193 ASSERT(m_rep);
194 }
195
196 size_t cost() const { return m_rep->cost(); }
197
198 private:
199 RefPtr<Rep> m_rep;
200
201 JS_EXPORTDATA static Rep* s_nullRep;
202 static UString* s_nullUString;
203
204 friend void initializeUString();
205 friend bool operator==(const UString&, const UString&);
206 };
207
208 ALWAYS_INLINE bool operator==(const UString& s1, const UString& s2)
209 {
210 int size = s1.size();
211 switch (size) {
212 case 0:
213 return !s2.size();
214 case 1:
215 return s2.size() == 1 && s1.data()[0] == s2.data()[0];
216 case 2: {
217 if (s2.size() != 2)
218 return false;
219 const UChar* d1 = s1.data();
220 const UChar* d2 = s2.data();
221 return (d1[0] == d2[0]) & (d1[1] == d2[1]);
222 }
223 default:
224 return s2.size() == size && memcmp(s1.data(), s2.data(), size * sizeof(UChar)) == 0;
225 }
226 }
227
228
229 inline bool operator!=(const UString& s1, const UString& s2)
230 {
231 return !JSC::operator==(s1, s2);
232 }
233
234 bool operator<(const UString& s1, const UString& s2);
235 bool operator>(const UString& s1, const UString& s2);
236
237 bool operator==(const UString& s1, const char* s2);
238
239 inline bool operator!=(const UString& s1, const char* s2)
240 {
241 return !JSC::operator==(s1, s2);
242 }
243
244 inline bool operator==(const char *s1, const UString& s2)
245 {
246 return operator==(s2, s1);
247 }
248
249 inline bool operator!=(const char *s1, const UString& s2)
250 {
251 return !JSC::operator==(s1, s2);
252 }
253
254 int compare(const UString&, const UString&);
255
256 inline UString::UString()
257 : m_rep(s_nullRep)
258 {
259 }
260
261 // Rule from ECMA 15.2 about what an array index is.
262 // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1.
263 inline unsigned UString::toArrayIndex(bool* ok) const
264 {
265 unsigned i = toStrictUInt32(ok);
266 if (ok && i >= 0xFFFFFFFFU)
267 *ok = false;
268 return i;
269 }
270
271 // We'd rather not do shared substring append for small strings, since
272 // this runs too much risk of a tiny initial string holding down a
273 // huge buffer.
274 // FIXME: this should be size_t but that would cause warnings until we
275 // fix UString sizes to be size_t instead of int
276 static const int minShareSize = Heap::minExtraCost / sizeof(UChar);
277
278 struct IdentifierRepHash : PtrHash<RefPtr<JSC::UString::Rep> > {
279 static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->existingHash(); }
280 static unsigned hash(JSC::UString::Rep* key) { return key->existingHash(); }
281 };
282
283 void initializeUString();
284
285 template<typename StringType>
286 class StringTypeAdapter {
287 };
288
289 template<>
290 class StringTypeAdapter<char*> {
291 public:
292 StringTypeAdapter<char*>(char* buffer)
293 : m_buffer((unsigned char*)buffer)
294 , m_length(strlen(buffer))
295 {
296 }
297
298 unsigned length() { return m_length; }
299
300 void writeTo(UChar* destination)
301 {
302 for (unsigned i = 0; i < m_length; ++i)
303 destination[i] = m_buffer[i];
304 }
305
306 private:
307 const unsigned char* m_buffer;
308 unsigned m_length;
309 };
310
311 template<>
312 class StringTypeAdapter<const char*> {
313 public:
314 StringTypeAdapter<const char*>(const char* buffer)
315 : m_buffer((unsigned char*)buffer)
316 , m_length(strlen(buffer))
317 {
318 }
319
320 unsigned length() { return m_length; }
321
322 void writeTo(UChar* destination)
323 {
324 for (unsigned i = 0; i < m_length; ++i)
325 destination[i] = m_buffer[i];
326 }
327
328 private:
329 const unsigned char* m_buffer;
330 unsigned m_length;
331 };
332
333 template<>
334 class StringTypeAdapter<UString> {
335 public:
336 StringTypeAdapter<UString>(UString& string)
337 : m_data(string.data())
338 , m_length(string.size())
339 {
340 }
341
342 unsigned length() { return m_length; }
343
344 void writeTo(UChar* destination)
345 {
346 for (unsigned i = 0; i < m_length; ++i)
347 destination[i] = m_data[i];
348 }
349
350 private:
351 const UChar* m_data;
352 unsigned m_length;
353 };
354
355 template<typename StringType1, typename StringType2>
356 UString makeString(StringType1 string1, StringType2 string2)
357 {
358 StringTypeAdapter<StringType1> adapter1(string1);
359 StringTypeAdapter<StringType2> adapter2(string2);
360
361 UChar* buffer;
362 unsigned length = adapter1.length() + adapter2.length();
363 PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
364 if (!resultImpl)
365 return UString();
366
367 UChar* result = buffer;
368 adapter1.writeTo(result);
369 result += adapter1.length();
370 adapter2.writeTo(result);
371
372 return resultImpl;
373 }
374
375 template<typename StringType1, typename StringType2, typename StringType3>
376 UString makeString(StringType1 string1, StringType2 string2, StringType3 string3)
377 {
378 StringTypeAdapter<StringType1> adapter1(string1);
379 StringTypeAdapter<StringType2> adapter2(string2);
380 StringTypeAdapter<StringType3> adapter3(string3);
381
382 UChar* buffer;
383 unsigned length = adapter1.length() + adapter2.length() + adapter3.length();
384 PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
385 if (!resultImpl)
386 return UString();
387
388 UChar* result = buffer;
389 adapter1.writeTo(result);
390 result += adapter1.length();
391 adapter2.writeTo(result);
392 result += adapter2.length();
393 adapter3.writeTo(result);
394
395 return resultImpl;
396 }
397
398 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
399 UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
400 {
401 StringTypeAdapter<StringType1> adapter1(string1);
402 StringTypeAdapter<StringType2> adapter2(string2);
403 StringTypeAdapter<StringType3> adapter3(string3);
404 StringTypeAdapter<StringType4> adapter4(string4);
405
406 UChar* buffer;
407 unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length();
408 PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
409 if (!resultImpl)
410 return UString();
411
412 UChar* result = buffer;
413 adapter1.writeTo(result);
414 result += adapter1.length();
415 adapter2.writeTo(result);
416 result += adapter2.length();
417 adapter3.writeTo(result);
418 result += adapter3.length();
419 adapter4.writeTo(result);
420
421 return resultImpl;
422 }
423
424 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
425 UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
426 {
427 StringTypeAdapter<StringType1> adapter1(string1);
428 StringTypeAdapter<StringType2> adapter2(string2);
429 StringTypeAdapter<StringType3> adapter3(string3);
430 StringTypeAdapter<StringType4> adapter4(string4);
431 StringTypeAdapter<StringType5> adapter5(string5);
432
433 UChar* buffer;
434 unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length();
435 PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
436 if (!resultImpl)
437 return UString();
438
439 UChar* result = buffer;
440 adapter1.writeTo(result);
441 result += adapter1.length();
442 adapter2.writeTo(result);
443 result += adapter2.length();
444 adapter3.writeTo(result);
445 result += adapter3.length();
446 adapter4.writeTo(result);
447 result += adapter4.length();
448 adapter5.writeTo(result);
449
450 return resultImpl;
451 }
452
453 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
454 UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
455 {
456 StringTypeAdapter<StringType1> adapter1(string1);
457 StringTypeAdapter<StringType2> adapter2(string2);
458 StringTypeAdapter<StringType3> adapter3(string3);
459 StringTypeAdapter<StringType4> adapter4(string4);
460 StringTypeAdapter<StringType5> adapter5(string5);
461 StringTypeAdapter<StringType6> adapter6(string6);
462
463 UChar* buffer;
464 unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length();
465 PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
466 if (!resultImpl)
467 return UString();
468
469 UChar* result = buffer;
470 adapter1.writeTo(result);
471 result += adapter1.length();
472 adapter2.writeTo(result);
473 result += adapter2.length();
474 adapter3.writeTo(result);
475 result += adapter3.length();
476 adapter4.writeTo(result);
477 result += adapter4.length();
478 adapter5.writeTo(result);
479 result += adapter5.length();
480 adapter6.writeTo(result);
481
482 return resultImpl;
483 }
484
485 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7>
486 UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7)
487 {
488 StringTypeAdapter<StringType1> adapter1(string1);
489 StringTypeAdapter<StringType2> adapter2(string2);
490 StringTypeAdapter<StringType3> adapter3(string3);
491 StringTypeAdapter<StringType4> adapter4(string4);
492 StringTypeAdapter<StringType5> adapter5(string5);
493 StringTypeAdapter<StringType6> adapter6(string6);
494 StringTypeAdapter<StringType7> adapter7(string7);
495
496 UChar* buffer;
497 unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length() + adapter7.length();
498 PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
499 if (!resultImpl)
500 return UString();
501
502 UChar* result = buffer;
503 adapter1.writeTo(result);
504 result += adapter1.length();
505 adapter2.writeTo(result);
506 result += adapter2.length();
507 adapter3.writeTo(result);
508 result += adapter3.length();
509 adapter4.writeTo(result);
510 result += adapter4.length();
511 adapter5.writeTo(result);
512 result += adapter5.length();
513 adapter6.writeTo(result);
514 result += adapter6.length();
515 adapter7.writeTo(result);
516
517 return resultImpl;
518 }
519
520 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8>
521 UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8)
522 {
523 StringTypeAdapter<StringType1> adapter1(string1);
524 StringTypeAdapter<StringType2> adapter2(string2);
525 StringTypeAdapter<StringType3> adapter3(string3);
526 StringTypeAdapter<StringType4> adapter4(string4);
527 StringTypeAdapter<StringType5> adapter5(string5);
528 StringTypeAdapter<StringType6> adapter6(string6);
529 StringTypeAdapter<StringType7> adapter7(string7);
530 StringTypeAdapter<StringType8> adapter8(string8);
531
532 UChar* buffer;
533 unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length() + adapter7.length() + adapter8.length();
534 PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
535 if (!resultImpl)
536 return UString();
537
538 UChar* result = buffer;
539 adapter1.writeTo(result);
540 result += adapter1.length();
541 adapter2.writeTo(result);
542 result += adapter2.length();
543 adapter3.writeTo(result);
544 result += adapter3.length();
545 adapter4.writeTo(result);
546 result += adapter4.length();
547 adapter5.writeTo(result);
548 result += adapter5.length();
549 adapter6.writeTo(result);
550 result += adapter6.length();
551 adapter7.writeTo(result);
552 result += adapter7.length();
553 adapter8.writeTo(result);
554
555 return resultImpl;
556 }
557
558} // namespace JSC
559
560namespace WTF {
561
562 template<typename T> struct DefaultHash;
563 template<typename T> struct StrHash;
564
565 template<> struct StrHash<JSC::UString::Rep*> {
566 static unsigned hash(const JSC::UString::Rep* key) { return key->hash(); }
567 static bool equal(const JSC::UString::Rep* a, const JSC::UString::Rep* b) { return JSC::equal(a, b); }
568 static const bool safeToCompareToEmptyOrDeleted = false;
569 };
570
571 template<> struct StrHash<RefPtr<JSC::UString::Rep> > : public StrHash<JSC::UString::Rep*> {
572 using StrHash<JSC::UString::Rep*>::hash;
573 static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->hash(); }
574 using StrHash<JSC::UString::Rep*>::equal;
575 static bool equal(const RefPtr<JSC::UString::Rep>& a, const RefPtr<JSC::UString::Rep>& b) { return JSC::equal(a.get(), b.get()); }
576 static bool equal(const JSC::UString::Rep* a, const RefPtr<JSC::UString::Rep>& b) { return JSC::equal(a, b.get()); }
577 static bool equal(const RefPtr<JSC::UString::Rep>& a, const JSC::UString::Rep* b) { return JSC::equal(a.get(), b); }
578
579 static const bool safeToCompareToEmptyOrDeleted = false;
580 };
581
582 template<> struct DefaultHash<JSC::UString::Rep*> {
583 typedef StrHash<JSC::UString::Rep*> Hash;
584 };
585
586 template<> struct DefaultHash<RefPtr<JSC::UString::Rep> > {
587 typedef StrHash<RefPtr<JSC::UString::Rep> > Hash;
588
589 };
590
591} // namespace WTF
592
593#endif
Note: See TracBrowser for help on using the repository browser.