Reviewed by Maciej.
[WebKit-https.git] / JavaScriptCore / 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) const;
85
86     bool toBoolean(ExecState *exec) const;
87     double toNumber(ExecState *exec) const;
88     UString toString(ExecState *exec) const;
89     JSObject *toObject(ExecState *exec) const;
90
91     // Integer conversions.
92     double toInteger(ExecState*) const;
93     double toIntegerPreserveNaN(ExecState*) const;
94     int32_t toInt32(ExecState*) const;
95     int32_t toInt32(ExecState*, bool& ok) const;
96     uint32_t toUInt32(ExecState*) const;
97     uint32_t toUInt32(ExecState*, bool& ok) const;
98
99     // Floating point conversions.
100     float toFloat(ExecState*) const;
101
102     // Garbage collection.
103     void mark();
104     bool marked() const;
105
106 private:
107     int32_t toInt32SlowCase(ExecState*, bool& ok) const;
108     uint32_t toUInt32SlowCase(ExecState*, bool& ok) const;
109
110     // Implementation details.
111     JSCell *asCell();
112     const JSCell *asCell() const;
113
114     // Give a compile time error if we try to copy one of these.
115     JSValue(const JSValue&);
116     JSValue& operator=(const JSValue&);
117 };
118
119 class JSCell : public JSValue {
120     friend class Collector;
121     friend class NumberImp;
122     friend class StringImp;
123     friend class JSObject;
124     friend class GetterSetterImp;
125 private:
126     JSCell();
127     virtual ~JSCell();
128 public:
129     // Querying the type.
130     virtual JSType type() const = 0;
131     bool isNumber() const;
132     bool isString() const;
133     bool isObject() const;
134     bool isObject(const ClassInfo *) const;
135
136     // Extracting the value.
137     bool getNumber(double&) const;
138     double getNumber() const; // NaN if not a number
139     bool getString(UString&) const;
140     UString getString() const; // null string if not a string
141     JSObject *getObject(); // NULL if not an object
142     const JSObject *getObject() const; // NULL if not an object
143
144     // Extracting integer values.
145     virtual bool getUInt32(uint32_t&) const;
146     virtual bool getTruncatedInt32(int32_t&) const;
147     virtual bool getTruncatedUInt32(uint32_t&) const;
148
149     // Basic conversions.
150     virtual JSValue *toPrimitive(ExecState *exec, JSType preferredType = UnspecifiedType) const = 0;
151     virtual bool getPrimitiveNumber(ExecState* exec, double& number) const = 0;
152     virtual bool toBoolean(ExecState *exec) const = 0;
153     virtual double toNumber(ExecState *exec) const = 0;
154     virtual UString toString(ExecState *exec) const = 0;
155     virtual JSObject *toObject(ExecState *exec) const = 0;
156
157     // Garbage collection.
158     void *operator new(size_t);
159     virtual void mark();
160     bool marked() const;
161 };
162
163 JSValue *jsNumberCell(double);
164
165 JSCell *jsString(const UString&); // returns empty string if passed null string
166 JSCell *jsString(const char* = ""); // returns empty string if passed 0
167
168 // should be used for strings that are owned by an object that will
169 // likely outlive the JSValue this makes, such as the parse tree or a
170 // DOM object that contains a UString
171 JSCell *jsOwnedString(const UString&); 
172
173 extern const double NaN;
174 extern const double Inf;
175
176 inline JSValue *jsUndefined()
177 {
178     return JSImmediate::undefinedImmediate();
179 }
180
181 inline JSValue *jsNull()
182 {
183     return JSImmediate::nullImmediate();
184 }
185
186 inline JSValue *jsNaN()
187 {
188     return JSImmediate::NaNImmediate();
189 }
190
191 inline JSValue *jsBoolean(bool b)
192 {
193     return b ? JSImmediate::trueImmediate() : JSImmediate::falseImmediate();
194 }
195
196 ALWAYS_INLINE JSValue* jsNumber(double d)
197 {
198     JSValue *v = JSImmediate::fromDouble(d);
199     return v ? v : jsNumberCell(d);
200 }
201
202 inline JSValue::JSValue()
203 {
204 }
205
206 inline JSValue::~JSValue()
207 {
208 }
209
210 inline JSCell::JSCell()
211 {
212 }
213
214 inline JSCell::~JSCell()
215 {
216 }
217
218 inline bool JSCell::isNumber() const
219 {
220     return type() == NumberType;
221 }
222
223 inline bool JSCell::isString() const
224 {
225     return type() == StringType;
226 }
227
228 inline bool JSCell::isObject() const
229 {
230     return type() == ObjectType;
231 }
232
233 inline bool JSCell::marked() const
234 {
235     return Collector::isCellMarked(this);
236 }
237
238 inline void JSCell::mark()
239 {
240     return Collector::markCell(this);
241 }
242
243 inline JSCell *JSValue::asCell()
244 {
245     ASSERT(!JSImmediate::isImmediate(this));
246     return static_cast<JSCell *>(this);
247 }
248
249 inline const JSCell *JSValue::asCell() const
250 {
251     ASSERT(!JSImmediate::isImmediate(this));
252     return static_cast<const JSCell *>(this);
253 }
254
255 inline bool JSValue::isUndefined() const
256 {
257     return this == jsUndefined();
258 }
259
260 inline bool JSValue::isNull() const
261 {
262     return this == jsNull();
263 }
264
265 inline bool JSValue::isUndefinedOrNull() const
266 {
267     return JSImmediate::isUndefinedOrNull(this);
268 }
269
270 inline bool JSValue::isBoolean() const
271 {
272     return JSImmediate::isBoolean(this);
273 }
274
275 inline bool JSValue::isNumber() const
276 {
277     return JSImmediate::isNumber(this) || !JSImmediate::isImmediate(this) && asCell()->isNumber();
278 }
279
280 inline bool JSValue::isString() const
281 {
282     return !JSImmediate::isImmediate(this) && asCell()->isString();
283 }
284
285 inline bool JSValue::isObject() const
286 {
287     return !JSImmediate::isImmediate(this) && asCell()->isObject();
288 }
289
290 inline bool JSValue::getBoolean(bool& v) const
291 {
292     if (JSImmediate::isBoolean(this)) {
293         v = JSImmediate::toBoolean(this);
294         return true;
295     }
296     
297     return false;
298 }
299
300 inline bool JSValue::getBoolean() const
301 {
302     return JSImmediate::isBoolean(this) ? JSImmediate::toBoolean(this) : false;
303 }
304
305 inline bool JSValue::getNumber(double& v) const
306 {
307     if (JSImmediate::isImmediate(this)) {
308         v = JSImmediate::toDouble(this);
309         return true;
310     }
311     return asCell()->getNumber(v);
312 }
313
314 inline double JSValue::getNumber() const
315 {
316     return JSImmediate::isImmediate(this) ? JSImmediate::toDouble(this) : asCell()->getNumber();
317 }
318
319 inline bool JSValue::getString(UString& s) const
320 {
321     return !JSImmediate::isImmediate(this) && asCell()->getString(s);
322 }
323
324 inline UString JSValue::getString() const
325 {
326     return JSImmediate::isImmediate(this) ? UString() : asCell()->getString();
327 }
328
329 inline JSObject *JSValue::getObject()
330 {
331     return JSImmediate::isImmediate(this) ? 0 : asCell()->getObject();
332 }
333
334 inline const JSObject *JSValue::getObject() const
335 {
336     return JSImmediate::isImmediate(this) ? 0 : asCell()->getObject();
337 }
338
339 ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
340 {
341     return JSImmediate::isImmediate(this) ? JSImmediate::getUInt32(this, v) : asCell()->getUInt32(v);
342 }
343
344 ALWAYS_INLINE bool JSValue::getTruncatedInt32(int32_t& v) const
345 {
346     return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedInt32(this, v) : asCell()->getTruncatedInt32(v);
347 }
348
349 inline bool JSValue::getTruncatedUInt32(uint32_t& v) const
350 {
351     return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedUInt32(this, v) : asCell()->getTruncatedUInt32(v);
352 }
353
354 inline void JSValue::mark()
355 {
356     ASSERT(!JSImmediate::isImmediate(this)); // callers should check !marked() before calling mark()
357     asCell()->mark();
358 }
359
360 inline bool JSValue::marked() const
361 {
362     return JSImmediate::isImmediate(this) || asCell()->marked();
363 }
364
365 inline JSType JSValue::type() const
366 {
367     return JSImmediate::isImmediate(this) ? JSImmediate::type(this) : asCell()->type();
368 }
369
370 inline JSValue* JSValue::toPrimitive(ExecState* exec, JSType preferredType) const
371 {
372     return JSImmediate::isImmediate(this) ? const_cast<JSValue*>(this) : asCell()->toPrimitive(exec, preferredType);
373 }
374
375 inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number) const
376 {
377     if (JSImmediate::isImmediate(this)) {
378         number = JSImmediate::toDouble(this);
379         return true;
380     }
381     return asCell()->getPrimitiveNumber(exec, number);
382 }
383
384 inline bool JSValue::toBoolean(ExecState *exec) const
385 {
386     return JSImmediate::isImmediate(this) ? JSImmediate::toBoolean(this) : asCell()->toBoolean(exec);
387 }
388
389 ALWAYS_INLINE double JSValue::toNumber(ExecState *exec) const
390 {
391     return JSImmediate::isImmediate(this) ? JSImmediate::toDouble(this) : asCell()->toNumber(exec);
392 }
393
394 inline UString JSValue::toString(ExecState *exec) const
395 {
396     return JSImmediate::isImmediate(this) ? JSImmediate::toString(this) : asCell()->toString(exec);
397 }
398
399 inline JSObject* JSValue::toObject(ExecState* exec) const
400 {
401     return JSImmediate::isImmediate(this) ? JSImmediate::toObject(this, exec) : asCell()->toObject(exec);
402 }
403
404 ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
405 {
406     int32_t i;
407     if (getTruncatedInt32(i))
408         return i;
409     bool ok;
410     return toInt32SlowCase(exec, ok);
411 }
412
413 inline uint32_t JSValue::toUInt32(ExecState* exec) const
414 {
415     uint32_t i;
416     if (getTruncatedUInt32(i))
417         return i;
418     bool ok;
419     return toUInt32SlowCase(exec, ok);
420 }
421
422 inline int32_t JSValue::toInt32(ExecState* exec, bool& ok) const
423 {
424     int32_t i;
425     if (getTruncatedInt32(i)) {
426         ok = true;
427         return i;
428     }
429     return toInt32SlowCase(exec, ok);
430 }
431
432 inline uint32_t JSValue::toUInt32(ExecState* exec, bool& ok) const
433 {
434     uint32_t i;
435     if (getTruncatedUInt32(i)) {
436         ok = true;
437         return i;
438     }
439     return toUInt32SlowCase(exec, ok);
440 }
441
442 } // namespace
443
444 #endif // KJS_VALUE_H