source: webkit/trunk/JavaScriptCore/runtime/JSString.cpp@ 67583

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

Rename UString::substr to substringSharingImpl, add to WTF::String.
Now WTF::String can do everything that JSC::UString can do!

Rubber stamped by Sam Weinig.

(JSC::escapeQuotes):

  • bytecompiler/NodesCodegen.cpp:

(JSC::substitute):

  • parser/SourceProvider.h:

(JSC::UStringSourceProvider::getRange):

  • runtime/FunctionPrototype.cpp:

(JSC::insertSemicolonIfNeeded):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::parseInt):

  • runtime/JSONObject.cpp:

(JSC::gap):
(JSC::Stringifier::indent):
(JSC::Stringifier::unindent):

  • runtime/JSString.cpp:

(JSC::JSString::replaceCharacter):

  • runtime/NumberPrototype.cpp:

(JSC::numberProtoFuncToFixed):
(JSC::numberProtoFuncToPrecision):

  • runtime/StringPrototype.cpp:

(JSC::stringProtoFuncReplace):
(JSC::trimString):

  • runtime/UString.cpp:

(JSC::UString::substringSharingImpl):

  • runtime/UString.h:
  • wtf/text/WTFString.cpp:

(WTF::String::substringSharingImpl):

  • wtf/text/WTFString.h:
  • Property svn:eol-style set to native
File size: 9.5 KB
Line 
1/*
2 * Copyright (C) 1999-2002 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
4 * Copyright (C) 2004, 2007, 2008 Apple 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#include "config.h"
24#include "JSString.h"
25
26#include "JSGlobalObject.h"
27#include "JSGlobalObjectFunctions.h"
28#include "JSObject.h"
29#include "Operations.h"
30#include "StringObject.h"
31#include "StringPrototype.h"
32
33namespace JSC {
34
35// Overview: this methods converts a JSString from holding a string in rope form
36// down to a simple UString representation. It does so by building up the string
37// backwards, since we want to avoid recursion, we expect that the tree structure
38// representing the rope is likely imbalanced with more nodes down the left side
39// (since appending to the string is likely more common) - and as such resolving
40// in this fashion should minimize work queue size. (If we built the queue forwards
41// we would likely have to place all of the constituent StringImpls into the
42// Vector before performing any concatenation, but by working backwards we likely
43// only fill the queue with the number of substrings at any given level in a
44// rope-of-ropes.)
45void JSString::resolveRope(ExecState* exec) const
46{
47 ASSERT(isRope());
48
49 // Allocate the buffer to hold the final string, position initially points to the end.
50 UChar* buffer;
51 if (PassRefPtr<StringImpl> newImpl = StringImpl::tryCreateUninitialized(m_length, buffer))
52 m_value = newImpl;
53 else {
54 for (unsigned i = 0; i < m_fiberCount; ++i) {
55 RopeImpl::deref(m_other.m_fibers[i]);
56 m_other.m_fibers[i] = 0;
57 }
58 m_fiberCount = 0;
59 ASSERT(!isRope());
60 ASSERT(m_value == UString());
61 if (exec)
62 throwOutOfMemoryError(exec);
63 return;
64 }
65 UChar* position = buffer + m_length;
66
67 // Start with the current RopeImpl.
68 Vector<RopeImpl::Fiber, 32> workQueue;
69 RopeImpl::Fiber currentFiber;
70 for (unsigned i = 0; i < (m_fiberCount - 1); ++i)
71 workQueue.append(m_other.m_fibers[i]);
72 currentFiber = m_other.m_fibers[m_fiberCount - 1];
73 while (true) {
74 if (RopeImpl::isRope(currentFiber)) {
75 RopeImpl* rope = static_cast<RopeImpl*>(currentFiber);
76 // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber'
77 // (we will be working backwards over the rope).
78 unsigned fiberCountMinusOne = rope->fiberCount() - 1;
79 for (unsigned i = 0; i < fiberCountMinusOne; ++i)
80 workQueue.append(rope->fibers()[i]);
81 currentFiber = rope->fibers()[fiberCountMinusOne];
82 } else {
83 StringImpl* string = static_cast<StringImpl*>(currentFiber);
84 unsigned length = string->length();
85 position -= length;
86 StringImpl::copyChars(position, string->characters(), length);
87
88 // Was this the last item in the work queue?
89 if (workQueue.isEmpty()) {
90 // Create a string from the UChar buffer, clear the rope RefPtr.
91 ASSERT(buffer == position);
92 for (unsigned i = 0; i < m_fiberCount; ++i) {
93 RopeImpl::deref(m_other.m_fibers[i]);
94 m_other.m_fibers[i] = 0;
95 }
96 m_fiberCount = 0;
97
98 ASSERT(!isRope());
99 return;
100 }
101
102 // No! - set the next item up to process.
103 currentFiber = workQueue.last();
104 workQueue.removeLast();
105 }
106 }
107}
108
109JSValue JSString::replaceCharacter(ExecState* exec, UChar character, const UString& replacement)
110{
111 if (!isRope()) {
112 size_t matchPosition = m_value.find(character);
113 if (matchPosition == notFound)
114 return JSValue(this);
115 return jsString(exec, m_value.substringSharingImpl(0, matchPosition), replacement, m_value.substringSharingImpl(matchPosition + 1));
116 }
117
118 RopeIterator end;
119
120 // Count total fibers and find matching string.
121 size_t fiberCount = 0;
122 StringImpl* matchString = 0;
123 size_t matchPosition = notFound;
124 for (RopeIterator it(m_other.m_fibers.data(), m_fiberCount); it != end; ++it) {
125 ++fiberCount;
126 if (matchString)
127 continue;
128
129 StringImpl* string = *it;
130 matchPosition = string->find(character);
131 if (matchPosition == notFound)
132 continue;
133 matchString = string;
134 }
135
136 if (!matchString)
137 return this;
138
139 RopeBuilder builder(replacement.length() ? fiberCount + 2 : fiberCount + 1);
140 if (UNLIKELY(builder.isOutOfMemory()))
141 return throwOutOfMemoryError(exec);
142
143 for (RopeIterator it(m_other.m_fibers.data(), m_fiberCount); it != end; ++it) {
144 StringImpl* string = *it;
145 if (string != matchString) {
146 builder.append(UString(string));
147 continue;
148 }
149
150 builder.append(UString(string).substringSharingImpl(0, matchPosition));
151 if (replacement.length())
152 builder.append(replacement);
153 builder.append(UString(string).substringSharingImpl(matchPosition + 1));
154 matchString = 0;
155 }
156
157 JSGlobalData* globalData = &exec->globalData();
158 return JSValue(new (globalData) JSString(globalData, builder.release()));
159}
160
161JSString* JSString::getIndexSlowCase(ExecState* exec, unsigned i)
162{
163 ASSERT(isRope());
164 resolveRope(exec);
165 // Return a safe no-value result, this should never be used, since the excetion will be thrown.
166 if (exec->exception())
167 return jsString(exec, "");
168 ASSERT(!isRope());
169 ASSERT(i < m_value.length());
170 return jsSingleCharacterSubstring(exec, m_value, i);
171}
172
173JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const
174{
175 return const_cast<JSString*>(this);
176}
177
178bool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result)
179{
180 result = this;
181 number = jsToNumber(value(exec));
182 return false;
183}
184
185bool JSString::toBoolean(ExecState*) const
186{
187 return m_length;
188}
189
190double JSString::toNumber(ExecState* exec) const
191{
192 return jsToNumber(value(exec));
193}
194
195UString JSString::toString(ExecState* exec) const
196{
197 return value(exec);
198}
199
200inline StringObject* StringObject::create(ExecState* exec, JSString* string)
201{
202 return new (exec) StringObject(exec->lexicalGlobalObject()->stringObjectStructure(), string);
203}
204
205JSObject* JSString::toObject(ExecState* exec) const
206{
207 return StringObject::create(exec, const_cast<JSString*>(this));
208}
209
210JSObject* JSString::toThisObject(ExecState* exec) const
211{
212 return StringObject::create(exec, const_cast<JSString*>(this));
213}
214
215bool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
216{
217 // The semantics here are really getPropertySlot, not getOwnPropertySlot.
218 // This function should only be called by JSValue::get.
219 if (getStringPropertySlot(exec, propertyName, slot))
220 return true;
221 if (propertyName == exec->propertyNames().underscoreProto) {
222 slot.setValue(exec->lexicalGlobalObject()->stringPrototype());
223 return true;
224 }
225 slot.setBase(this);
226 JSObject* object;
227 for (JSValue prototype = exec->lexicalGlobalObject()->stringPrototype(); !prototype.isNull(); prototype = object->prototype()) {
228 object = asObject(prototype);
229 if (object->getOwnPropertySlot(exec, propertyName, slot))
230 return true;
231 }
232 slot.setUndefined();
233 return true;
234}
235
236bool JSString::getStringPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
237{
238 if (propertyName == exec->propertyNames().length) {
239 descriptor.setDescriptor(jsNumber(exec, m_length), DontEnum | DontDelete | ReadOnly);
240 return true;
241 }
242
243 bool isStrictUInt32;
244 unsigned i = propertyName.toUInt32(isStrictUInt32);
245 if (isStrictUInt32 && i < m_length) {
246 descriptor.setDescriptor(getIndex(exec, i), DontDelete | ReadOnly);
247 return true;
248 }
249
250 return false;
251}
252
253bool JSString::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
254{
255 if (getStringPropertyDescriptor(exec, propertyName, descriptor))
256 return true;
257 if (propertyName != exec->propertyNames().underscoreProto)
258 return false;
259 descriptor.setDescriptor(exec->lexicalGlobalObject()->stringPrototype(), DontEnum);
260 return true;
261}
262
263bool JSString::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
264{
265 // The semantics here are really getPropertySlot, not getOwnPropertySlot.
266 // This function should only be called by JSValue::get.
267 if (getStringPropertySlot(exec, propertyName, slot))
268 return true;
269 return JSString::getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot);
270}
271
272} // namespace JSC
Note: See TracBrowser for help on using the repository browser.