]> git.saurik.com Git - apple/javascriptcore.git/blob - kjs/value.h
JavaScriptCore-466.1.tar.gz
[apple/javascriptcore.git] / kjs / value.h
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