#ifndef _KJS_VALUE_H_
#define _KJS_VALUE_H_
#define USE_CONSERVATIVE_GC 1
#define TEST_CONSERVATIVE_GC 0
#ifndef NDEBUG // protection against problems if committing with KJS_VERBOSE on
#endif
#include <stdlib.h> // Needed for size_t
#include "ustring.h"
#include "simple_number.h"
namespace KJS {
class Value;
class ValueImp;
class ValueImpPrivate;
class Undefined;
class UndefinedImp;
class Null;
class NullImp;
class Boolean;
class BooleanImp;
class String;
class StringImp;
class Number;
class NumberImp;
class Object;
class ObjectImp;
class Reference;
class ReferenceImp;
class List;
class ListImp;
class Completion;
class ExecState;
enum Type {
UnspecifiedType = 0,
UndefinedType = 1,
NullType = 2,
BooleanType = 3,
StringType = 4,
NumberType = 5,
ObjectType = 6
};
class ValueImp {
friend class Collector;
friend class Value;
friend class ContextImp;
friend class FunctionCallNode;
public:
#if USE_CONSERVATIVE_GC
explicit ValueImp(bool destructorIsThreadSafe = true) : _destructorIsThreadSafe(destructorIsThreadSafe), _marked(0) {}
virtual ~ValueImp() {}
#else
ValueImp();
virtual ~ValueImp();
#endif
#if !USE_CONSERVATIVE_GC
ValueImp* ref() { if (!SimpleNumber::is(this)) refcount++; return this; }
bool deref() { if (SimpleNumber::is(this)) return false; else return (!--refcount); }
#endif
virtual void mark();
bool marked() const;
void* operator new(size_t);
void operator delete(void*);
#if !USE_CONSERVATIVE_GC
void setGcAllowed();
void setGcAllowedFast() { _flags |= VI_GCALLOWED; }
#endif
double toInteger(ExecState *exec) const;
int32_t toInt32(ExecState *exec) const;
uint32_t toUInt32(ExecState *exec) const;
uint16_t toUInt16(ExecState *exec) const;
Type dispatchType() const;
Value dispatchToPrimitive(ExecState *exec, Type preferredType = UnspecifiedType) const;
bool dispatchToBoolean(ExecState *exec) const;
double dispatchToNumber(ExecState *exec) const;
double dispatchToNumber(ExecState *exec, bool &knownToBeInteger) const;
UString dispatchToString(ExecState *exec) const;
bool dispatchToUInt32(uint32_t&) const;
Object dispatchToObject(ExecState *exec) const;
#if !USE_CONSERVATIVE_GC
unsigned short int refcount;
#endif
private:
virtual Type type() const = 0;
virtual Value toPrimitive(ExecState *exec, Type preferredType = UnspecifiedType) const = 0;
virtual bool toBoolean(ExecState *exec) const = 0;
virtual double toNumber(ExecState *exec) const = 0;
virtual UString toString(ExecState *exec) const = 0;
virtual Object toObject(ExecState *exec) const = 0;
virtual bool toUInt32(unsigned&) const;
#if USE_CONSERVATIVE_GC
bool _destructorIsThreadSafe : 1;
bool _marked : 1;
#else
unsigned short int _flags;
enum {
VI_MARKED = 1,
VI_GCALLOWED = 2,
VI_CREATED = 4
#if TEST_CONSERVATIVE_GC
, VI_CONSERVATIVE_MARKED = 8
#endif // TEST_CONSERVATIVE_GC
}; #endif // USE_CONSERVATIVE_GC
ValueImp(const ValueImp&);
ValueImp& operator=(const ValueImp&);
#if TEST_CONSERVATIVE_GC
static void useConservativeMark(bool);
#endif
};
class Value {
public:
Value() : rep(0) { }
#if USE_CONSERVATIVE_GC
explicit Value(ValueImp *v) : rep(v) {}
Value(const Value &v) : rep (v.rep) {}
~Value() {}
Value& operator=(const Value &v) { rep = v.rep; return *this; }
#else
explicit Value(ValueImp *v);
Value(const Value &v);
~Value();
Value& operator=(const Value &v);
#endif
explicit Value(bool);
explicit Value(int);
explicit Value(unsigned);
explicit Value(double);
explicit Value(long);
explicit Value(unsigned long);
Value(double, bool knownToBeInteger);
explicit Value(const char *);
Value(const UString &);
bool isNull() const { return rep == 0; }
ValueImp *imp() const { return rep; }
Type type() const { return rep->dispatchType(); }
bool isA(Type t) const { return rep->dispatchType() == t; }
Value toPrimitive(ExecState *exec,
Type preferredType = UnspecifiedType) const
{ return rep->dispatchToPrimitive(exec, preferredType); }
bool toBoolean(ExecState *exec) const { return rep->dispatchToBoolean(exec); }
double toNumber(ExecState *exec) const { return rep->dispatchToNumber(exec); }
double toNumber(ExecState *exec, bool &knownToBeInteger) const { return rep->dispatchToNumber(exec, knownToBeInteger); }
double toInteger(ExecState *exec) const { return rep->toInteger(exec); }
int32_t toInt32(ExecState *exec) const { return rep->toInt32(exec); }
uint32_t toUInt32(ExecState *exec) const { return rep->toUInt32(exec); }
uint16_t toUInt16(ExecState *exec) const { return rep->toUInt16(exec); }
UString toString(ExecState *exec) const { return rep->dispatchToString(exec); }
Object toObject(ExecState *exec) const;
bool toUInt32(uint32_t& i) const { return rep->dispatchToUInt32(i); }
protected:
ValueImp *rep;
};
class Undefined : public Value {
public:
Undefined();
static Undefined dynamicCast(const Value &v);
private:
friend class UndefinedImp;
explicit Undefined(UndefinedImp *v);
};
class Null : public Value {
public:
Null();
static Null dynamicCast(const Value &v);
private:
friend class NullImp;
explicit Null(NullImp *v);
};
class Boolean : public Value {
public:
Boolean(bool b = false);
static Boolean dynamicCast(const Value &v);
bool value() const;
private:
friend class BooleanImp;
explicit Boolean(BooleanImp *v);
};
class String : public Value {
public:
String(const UString &s = "");
static String dynamicCast(const Value &v);
UString value() const;
private:
friend class StringImp;
explicit String(StringImp *v);
};
extern const double NaN;
extern const double Inf;
class Number : public Value {
friend class ValueImp;
public:
Number(int i);
Number(unsigned int u);
Number(double d = 0.0);
Number(long int l);
Number(long unsigned int l);
Number(double d, bool knownToBeInteger);
double value() const;
int intValue() const;
bool isNaN() const;
bool isInf() const;
static Number dynamicCast(const Value &v);
private:
friend class NumberImp;
explicit Number(NumberImp *v);
};
inline bool ValueImp::marked() const
{
#if USE_CONSERVATIVE_GC
return SimpleNumber::is(this) || _marked;
#elif TEST_CONSERVATIVE_GC
if (conservativeMark) {
return SimpleNumber::is(this) || (_flags & VI_CONSERVATIVE_MARKED);
} else {
return SimpleNumber::is(this) || (_flags & VI_MARKED);
}
#else
return SimpleNumber::is(this) || (_flags & VI_MARKED);
#endif
}
inline Type ValueImp::dispatchType() const
{
if (SimpleNumber::is(this))
return NumberType;
return type();
}
inline Value ValueImp::dispatchToPrimitive(ExecState *exec, Type preferredType) const
{
if (SimpleNumber::is(this))
return Value(const_cast<ValueImp *>(this));
return toPrimitive(exec, preferredType);
}
inline bool ValueImp::dispatchToBoolean(ExecState *exec) const
{
if (SimpleNumber::is(this))
return SimpleNumber::value(this);
return toBoolean(exec);
}
inline double ValueImp::dispatchToNumber(ExecState *exec) const
{
if (SimpleNumber::is(this))
return SimpleNumber::value(this);
return toNumber(exec);
}
inline double ValueImp::dispatchToNumber(ExecState *exec, bool &knownToBeInteger) const
{
if (SimpleNumber::is(this)) {
knownToBeInteger = true;
return SimpleNumber::value(this);
}
knownToBeInteger = false;
return toNumber(exec);
}
inline UString ValueImp::dispatchToString(ExecState *exec) const
{
if (SimpleNumber::is(this))
return UString::from(SimpleNumber::value(this));
return toString(exec);
}
inline bool ValueImp::dispatchToUInt32(uint32_t& result) const
{
if (SimpleNumber::is(this)) {
long i = SimpleNumber::value(this);
if (i < 0)
return false;
result = i;
return true;
}
return toUInt32(result);
}
}
#endif // _KJS_VALUE_H_