]>
Commit | Line | Data |
---|---|---|
b37bf2e1 A |
1 | /* |
2 | * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) | |
3 | * Copyright (C) 2001 Peter Kelly (pmk@post.com) | |
4 | * Copyright (C) 2003, 2004, 2005, 2007 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 | #ifndef KJS_VALUE_H | |
24 | #define KJS_VALUE_H | |
25 | ||
26 | #include "JSImmediate.h" | |
27 | #include "collector.h" | |
28 | #include "ustring.h" | |
29 | #include <stddef.h> // for size_t | |
30 | ||
31 | namespace KJS { | |
32 | ||
33 | class ExecState; | |
34 | class JSObject; | |
35 | class JSCell; | |
36 | ||
37 | struct ClassInfo; | |
38 | ||
39 | /** | |
40 | * JSValue is the base type for all primitives (Undefined, Null, Boolean, | |
41 | * String, Number) and objects in ECMAScript. | |
42 | * | |
43 | * Note: you should never inherit from JSValue as it is for primitive types | |
44 | * only (all of which are provided internally by KJS). Instead, inherit from | |
45 | * JSObject. | |
46 | */ | |
47 | class JSValue : Noncopyable { | |
48 | friend class JSCell; // so it can derive from this class | |
49 | friend class Collector; // so it can call asCell() | |
50 | ||
51 | private: | |
52 | JSValue(); | |
53 | virtual ~JSValue(); | |
54 | ||
55 | public: | |
56 | // Querying the type. | |
57 | JSType type() const; | |
58 | bool isUndefined() const; | |
59 | bool isNull() const; | |
60 | bool isUndefinedOrNull() const; | |
61 | bool isBoolean() const; | |
62 | bool isNumber() const; | |
63 | bool isString() const; | |
64 | bool isObject() const; | |
65 | bool isObject(const ClassInfo *) const; | |
66 | ||
67 | // Extracting the value. | |
68 | bool getBoolean(bool&) const; | |
69 | bool getBoolean() const; // false if not a boolean | |
70 | bool getNumber(double&) const; | |
71 | double getNumber() const; // NaN if not a number | |
72 | bool getString(UString&) const; | |
73 | UString getString() const; // null string if not a string | |
74 | JSObject *getObject(); // NULL if not an object | |
75 | const JSObject *getObject() const; // NULL if not an object | |
76 | ||
77 | // Extracting integer values. | |
78 | bool getUInt32(uint32_t&) const; | |
79 | bool getTruncatedInt32(int32_t&) const; | |
80 | bool getTruncatedUInt32(uint32_t&) const; | |
81 | ||
82 | // Basic conversions. | |
83 | JSValue* toPrimitive(ExecState* exec, JSType preferredType = UnspecifiedType) const; | |
84 | bool getPrimitiveNumber(ExecState* exec, double& number, JSValue*& value); | |
85 | ||
86 | bool toBoolean(ExecState *exec) const; | |
87 | double toNumber(ExecState *exec) const; | |
88 | JSValue* toJSNumber(ExecState*) const; // Fast path for when you expect that the value is an immediate number. | |
89 | UString toString(ExecState *exec) const; | |
90 | JSObject *toObject(ExecState *exec) const; | |
91 | ||
92 | // Integer conversions. | |
93 | double toInteger(ExecState*) const; | |
94 | double toIntegerPreserveNaN(ExecState*) const; | |
95 | int32_t toInt32(ExecState*) const; | |
96 | int32_t toInt32(ExecState*, bool& ok) const; | |
97 | uint32_t toUInt32(ExecState*) const; | |
98 | uint32_t toUInt32(ExecState*, bool& ok) const; | |
99 | ||
100 | // These are identical logic to above, and faster than jsNumber(number)->toInt32(exec) | |
101 | static int32_t toInt32(double); | |
102 | static int32_t toUInt32(double); | |
103 | ||
104 | // Floating point conversions. | |
105 | float toFloat(ExecState*) const; | |
106 | ||
107 | // Garbage collection. | |
108 | void mark(); | |
109 | bool marked() const; | |
110 | ||
111 | static int32_t toInt32SlowCase(double, bool& ok); | |
112 | static uint32_t toUInt32SlowCase(double, bool& ok); | |
113 | ||
114 | private: | |
115 | int32_t toInt32SlowCase(ExecState*, bool& ok) const; | |
116 | uint32_t toUInt32SlowCase(ExecState*, bool& ok) const; | |
117 | ||
118 | // Implementation details. | |
119 | JSCell *asCell(); | |
120 | const JSCell *asCell() const; | |
121 | ||
122 | // Give a compile time error if we try to copy one of these. | |
123 | JSValue(const JSValue&); | |
124 | JSValue& operator=(const JSValue&); | |
125 | }; | |
126 | ||
127 | class JSCell : public JSValue { | |
128 | friend class Collector; | |
129 | friend class NumberImp; | |
130 | friend class StringImp; | |
131 | friend class JSObject; | |
132 | friend class GetterSetterImp; | |
133 | private: | |
134 | JSCell(); | |
135 | virtual ~JSCell(); | |
136 | public: | |
137 | // Querying the type. | |
138 | virtual JSType type() const = 0; | |
139 | bool isNumber() const; | |
140 | bool isString() const; | |
141 | bool isObject() const; | |
142 | bool isObject(const ClassInfo *) const; | |
143 | ||
144 | // Extracting the value. | |
145 | bool getNumber(double&) const; | |
146 | double getNumber() const; // NaN if not a number | |
147 | bool getString(UString&) const; | |
148 | UString getString() const; // null string if not a string | |
149 | JSObject *getObject(); // NULL if not an object | |
150 | const JSObject *getObject() const; // NULL if not an object | |
151 | ||
152 | // Extracting integer values. | |
153 | virtual bool getUInt32(uint32_t&) const; | |
154 | virtual bool getTruncatedInt32(int32_t&) const; | |
155 | virtual bool getTruncatedUInt32(uint32_t&) const; | |
156 | ||
157 | // Basic conversions. | |
158 | virtual JSValue *toPrimitive(ExecState *exec, JSType preferredType = UnspecifiedType) const = 0; | |
159 | virtual bool getPrimitiveNumber(ExecState* exec, double& number, JSValue*& value) = 0; | |
160 | virtual bool toBoolean(ExecState *exec) const = 0; | |
161 | virtual double toNumber(ExecState *exec) const = 0; | |
162 | virtual UString toString(ExecState *exec) const = 0; | |
163 | virtual JSObject *toObject(ExecState *exec) const = 0; | |
164 | ||
165 | // Garbage collection. | |
166 | void *operator new(size_t); | |
167 | virtual void mark(); | |
168 | bool marked() const; | |
169 | }; | |
170 | ||
171 | JSValue *jsNumberCell(double); | |
172 | ||
173 | JSCell *jsString(const UString&); // returns empty string if passed null string | |
174 | JSCell *jsString(const char* = ""); // returns empty string if passed 0 | |
175 | ||
176 | // should be used for strings that are owned by an object that will | |
177 | // likely outlive the JSValue this makes, such as the parse tree or a | |
178 | // DOM object that contains a UString | |
179 | JSCell *jsOwnedString(const UString&); | |
180 | ||
181 | extern const double NaN; | |
182 | extern const double Inf; | |
183 | ||
184 | inline JSValue *jsUndefined() | |
185 | { | |
186 | return JSImmediate::undefinedImmediate(); | |
187 | } | |
188 | ||
189 | inline JSValue *jsNull() | |
190 | { | |
191 | return JSImmediate::nullImmediate(); | |
192 | } | |
193 | ||
194 | inline JSValue *jsNaN() | |
195 | { | |
196 | static const union { | |
197 | uint64_t bits; | |
198 | double d; | |
199 | } nan = { 0x7ff80000ULL << 32 }; | |
200 | return jsNumberCell(nan.d); | |
201 | } | |
202 | ||
203 | inline JSValue *jsBoolean(bool b) | |
204 | { | |
205 | return b ? JSImmediate::trueImmediate() : JSImmediate::falseImmediate(); | |
206 | } | |
207 | ||
208 | ALWAYS_INLINE JSValue* jsNumber(double d) | |
209 | { | |
210 | JSValue* v = JSImmediate::from(d); | |
211 | return v ? v : jsNumberCell(d); | |
212 | } | |
213 | ||
214 | ALWAYS_INLINE JSValue* jsNumber(int i) | |
215 | { | |
216 | JSValue* v = JSImmediate::from(i); | |
217 | return v ? v : jsNumberCell(i); | |
218 | } | |
219 | ||
220 | ALWAYS_INLINE JSValue* jsNumber(unsigned i) | |
221 | { | |
222 | JSValue* v = JSImmediate::from(i); | |
223 | return v ? v : jsNumberCell(i); | |
224 | } | |
225 | ||
226 | ALWAYS_INLINE JSValue* jsNumber(long i) | |
227 | { | |
228 | JSValue* v = JSImmediate::from(i); | |
229 | return v ? v : jsNumberCell(i); | |
230 | } | |
231 | ||
232 | ALWAYS_INLINE JSValue* jsNumber(unsigned long i) | |
233 | { | |
234 | JSValue* v = JSImmediate::from(i); | |
235 | return v ? v : jsNumberCell(i); | |
236 | } | |
237 | ||
238 | ALWAYS_INLINE JSValue* jsNumber(long long i) | |
239 | { | |
240 | JSValue* v = JSImmediate::from(i); | |
241 | return v ? v : jsNumberCell(static_cast<double>(i)); | |
242 | } | |
243 | ||
244 | ALWAYS_INLINE JSValue* jsNumber(unsigned long long i) | |
245 | { | |
246 | JSValue* v = JSImmediate::from(i); | |
247 | return v ? v : jsNumberCell(static_cast<double>(i)); | |
248 | } | |
249 | ||
250 | ALWAYS_INLINE JSValue* jsNumberFromAnd(ExecState *exec, JSValue* v1, JSValue* v2) | |
251 | { | |
252 | if (JSImmediate::areBothImmediateNumbers(v1, v2)) | |
253 | return JSImmediate::andImmediateNumbers(v1, v2); | |
254 | return jsNumber(v1->toInt32(exec) & v2->toInt32(exec)); | |
255 | } | |
256 | ||
257 | inline JSValue::JSValue() | |
258 | { | |
259 | } | |
260 | ||
261 | inline JSValue::~JSValue() | |
262 | { | |
263 | } | |
264 | ||
265 | inline JSCell::JSCell() | |
266 | { | |
267 | } | |
268 | ||
269 | inline JSCell::~JSCell() | |
270 | { | |
271 | } | |
272 | ||
273 | inline bool JSCell::isNumber() const | |
274 | { | |
275 | return type() == NumberType; | |
276 | } | |
277 | ||
278 | inline bool JSCell::isString() const | |
279 | { | |
280 | return type() == StringType; | |
281 | } | |
282 | ||
283 | inline bool JSCell::isObject() const | |
284 | { | |
285 | return type() == ObjectType; | |
286 | } | |
287 | ||
288 | inline bool JSCell::marked() const | |
289 | { | |
290 | return Collector::isCellMarked(this); | |
291 | } | |
292 | ||
293 | inline void JSCell::mark() | |
294 | { | |
295 | return Collector::markCell(this); | |
296 | } | |
297 | ||
298 | ALWAYS_INLINE JSCell* JSValue::asCell() | |
299 | { | |
300 | ASSERT(!JSImmediate::isImmediate(this)); | |
301 | return static_cast<JSCell*>(this); | |
302 | } | |
303 | ||
304 | ALWAYS_INLINE const JSCell* JSValue::asCell() const | |
305 | { | |
306 | ASSERT(!JSImmediate::isImmediate(this)); | |
307 | return static_cast<const JSCell*>(this); | |
308 | } | |
309 | ||
310 | inline bool JSValue::isUndefined() const | |
311 | { | |
312 | return this == jsUndefined(); | |
313 | } | |
314 | ||
315 | inline bool JSValue::isNull() const | |
316 | { | |
317 | return this == jsNull(); | |
318 | } | |
319 | ||
320 | inline bool JSValue::isUndefinedOrNull() const | |
321 | { | |
322 | return JSImmediate::isUndefinedOrNull(this); | |
323 | } | |
324 | ||
325 | inline bool JSValue::isBoolean() const | |
326 | { | |
327 | return JSImmediate::isBoolean(this); | |
328 | } | |
329 | ||
330 | inline bool JSValue::isNumber() const | |
331 | { | |
332 | return JSImmediate::isNumber(this) || (!JSImmediate::isImmediate(this) && asCell()->isNumber()); | |
333 | } | |
334 | ||
335 | inline bool JSValue::isString() const | |
336 | { | |
337 | return !JSImmediate::isImmediate(this) && asCell()->isString(); | |
338 | } | |
339 | ||
340 | inline bool JSValue::isObject() const | |
341 | { | |
342 | return !JSImmediate::isImmediate(this) && asCell()->isObject(); | |
343 | } | |
344 | ||
345 | inline bool JSValue::getBoolean(bool& v) const | |
346 | { | |
347 | if (JSImmediate::isBoolean(this)) { | |
348 | v = JSImmediate::toBoolean(this); | |
349 | return true; | |
350 | } | |
351 | ||
352 | return false; | |
353 | } | |
354 | ||
355 | inline bool JSValue::getBoolean() const | |
356 | { | |
357 | return JSImmediate::isBoolean(this) ? JSImmediate::toBoolean(this) : false; | |
358 | } | |
359 | ||
360 | inline bool JSValue::getNumber(double& v) const | |
361 | { | |
362 | if (JSImmediate::isImmediate(this)) { | |
363 | v = JSImmediate::toDouble(this); | |
364 | return true; | |
365 | } | |
366 | return asCell()->getNumber(v); | |
367 | } | |
368 | ||
369 | inline double JSValue::getNumber() const | |
370 | { | |
371 | return JSImmediate::isImmediate(this) ? JSImmediate::toDouble(this) : asCell()->getNumber(); | |
372 | } | |
373 | ||
374 | inline bool JSValue::getString(UString& s) const | |
375 | { | |
376 | return !JSImmediate::isImmediate(this) && asCell()->getString(s); | |
377 | } | |
378 | ||
379 | inline UString JSValue::getString() const | |
380 | { | |
381 | return JSImmediate::isImmediate(this) ? UString() : asCell()->getString(); | |
382 | } | |
383 | ||
384 | inline JSObject *JSValue::getObject() | |
385 | { | |
386 | return JSImmediate::isImmediate(this) ? 0 : asCell()->getObject(); | |
387 | } | |
388 | ||
389 | inline const JSObject *JSValue::getObject() const | |
390 | { | |
391 | return JSImmediate::isImmediate(this) ? 0 : asCell()->getObject(); | |
392 | } | |
393 | ||
394 | ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const | |
395 | { | |
396 | return JSImmediate::isImmediate(this) ? JSImmediate::getUInt32(this, v) : asCell()->getUInt32(v); | |
397 | } | |
398 | ||
399 | ALWAYS_INLINE bool JSValue::getTruncatedInt32(int32_t& v) const | |
400 | { | |
401 | return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedInt32(this, v) : asCell()->getTruncatedInt32(v); | |
402 | } | |
403 | ||
404 | inline bool JSValue::getTruncatedUInt32(uint32_t& v) const | |
405 | { | |
406 | return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedUInt32(this, v) : asCell()->getTruncatedUInt32(v); | |
407 | } | |
408 | ||
409 | inline void JSValue::mark() | |
410 | { | |
411 | ASSERT(!JSImmediate::isImmediate(this)); // callers should check !marked() before calling mark() | |
412 | asCell()->mark(); | |
413 | } | |
414 | ||
415 | inline bool JSValue::marked() const | |
416 | { | |
417 | return JSImmediate::isImmediate(this) || asCell()->marked(); | |
418 | } | |
419 | ||
420 | inline JSType JSValue::type() const | |
421 | { | |
422 | return JSImmediate::isImmediate(this) ? JSImmediate::type(this) : asCell()->type(); | |
423 | } | |
424 | ||
425 | inline JSValue* JSValue::toPrimitive(ExecState* exec, JSType preferredType) const | |
426 | { | |
427 | return JSImmediate::isImmediate(this) ? const_cast<JSValue*>(this) : asCell()->toPrimitive(exec, preferredType); | |
428 | } | |
429 | ||
430 | inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue*& value) | |
431 | { | |
432 | if (JSImmediate::isImmediate(this)) { | |
433 | number = JSImmediate::toDouble(this); | |
434 | value = this; | |
435 | return true; | |
436 | } | |
437 | return asCell()->getPrimitiveNumber(exec, number, value); | |
438 | } | |
439 | ||
440 | inline bool JSValue::toBoolean(ExecState *exec) const | |
441 | { | |
442 | return JSImmediate::isImmediate(this) ? JSImmediate::toBoolean(this) : asCell()->toBoolean(exec); | |
443 | } | |
444 | ||
445 | ALWAYS_INLINE double JSValue::toNumber(ExecState *exec) const | |
446 | { | |
447 | return JSImmediate::isImmediate(this) ? JSImmediate::toDouble(this) : asCell()->toNumber(exec); | |
448 | } | |
449 | ||
450 | ALWAYS_INLINE JSValue* JSValue::toJSNumber(ExecState* exec) const | |
451 | { | |
452 | return JSImmediate::isNumber(this) ? const_cast<JSValue*>(this) : jsNumber(this->toNumber(exec)); | |
453 | } | |
454 | ||
455 | inline UString JSValue::toString(ExecState *exec) const | |
456 | { | |
457 | return JSImmediate::isImmediate(this) ? JSImmediate::toString(this) : asCell()->toString(exec); | |
458 | } | |
459 | ||
460 | inline JSObject* JSValue::toObject(ExecState* exec) const | |
461 | { | |
462 | return JSImmediate::isImmediate(this) ? JSImmediate::toObject(this, exec) : asCell()->toObject(exec); | |
463 | } | |
464 | ||
465 | ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const | |
466 | { | |
467 | int32_t i; | |
468 | if (getTruncatedInt32(i)) | |
469 | return i; | |
470 | bool ok; | |
471 | return toInt32SlowCase(exec, ok); | |
472 | } | |
473 | ||
474 | inline uint32_t JSValue::toUInt32(ExecState* exec) const | |
475 | { | |
476 | uint32_t i; | |
477 | if (getTruncatedUInt32(i)) | |
478 | return i; | |
479 | bool ok; | |
480 | return toUInt32SlowCase(exec, ok); | |
481 | } | |
482 | ||
483 | inline int32_t JSValue::toInt32(double val) | |
484 | { | |
485 | if (!(val >= -2147483648.0 && val < 2147483648.0)) { | |
486 | bool ignored; | |
487 | return toInt32SlowCase(val, ignored); | |
488 | } | |
489 | return static_cast<int32_t>(val); | |
490 | } | |
491 | ||
492 | inline int32_t JSValue::toUInt32(double val) | |
493 | { | |
494 | if (!(val >= 0.0 && val < 4294967296.0)) { | |
495 | bool ignored; | |
496 | return toUInt32SlowCase(val, ignored); | |
497 | } | |
498 | return static_cast<uint32_t>(val); | |
499 | } | |
500 | ||
501 | inline int32_t JSValue::toInt32(ExecState* exec, bool& ok) const | |
502 | { | |
503 | int32_t i; | |
504 | if (getTruncatedInt32(i)) { | |
505 | ok = true; | |
506 | return i; | |
507 | } | |
508 | return toInt32SlowCase(exec, ok); | |
509 | } | |
510 | ||
511 | inline uint32_t JSValue::toUInt32(ExecState* exec, bool& ok) const | |
512 | { | |
513 | uint32_t i; | |
514 | if (getTruncatedUInt32(i)) { | |
515 | ok = true; | |
516 | return i; | |
517 | } | |
518 | return toUInt32SlowCase(exec, ok); | |
519 | } | |
520 | ||
521 | } // namespace | |
522 | ||
523 | #endif // KJS_VALUE_H |