blob: bcea639b6f13efe1ad907c2e4c17012d5ef12550 [file] [log] [blame]
#ifndef _H_Value
#define _H_Value
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
#ifndef _WINDOWS
// TODO(jat): remove; for abort() which should probably go away
#include <stdlib.h>
#endif
#include <string>
#include "Debug.h"
#include "BrowserChannel.h"
class Value {
public:
enum ValueType {
NULL_TYPE = VALUE_TYPE_NULL,
BOOLEAN = VALUE_TYPE_BOOLEAN,
BYTE = VALUE_TYPE_BYTE,
CHAR = VALUE_TYPE_CHAR,
SHORT = VALUE_TYPE_SHORT,
INT = VALUE_TYPE_INT,
LONG = VALUE_TYPE_LONG,
FLOAT = VALUE_TYPE_FLOAT,
DOUBLE = VALUE_TYPE_DOUBLE,
STRING = VALUE_TYPE_STRING,
JAVA_OBJECT = VALUE_TYPE_JAVA_OBJECT,
JS_OBJECT = VALUE_TYPE_JS_OBJECT,
UNDEFINED = VALUE_TYPE_UNDEFINED
};
private:
ValueType type;
union {
bool boolValue;
unsigned char byteValue;
unsigned short charValue;
double doubleValue;
float floatValue;
int32_t intValue;
int64_t longValue;
short shortValue;
std::string* stringValue;
} value;
public:
Value() {
type = UNDEFINED;
}
Value(const Value& other) {
copyValue(other);
}
Value& operator=(const Value& other) {
clearOldValue();
copyValue(other);
return *this;
}
~Value() {
clearOldValue();
}
bool getBoolean() const {
assertType(BOOLEAN);
return value.boolValue;
}
unsigned char getByte() const {
assertType(BYTE);
return value.byteValue;
}
unsigned short getChar() const {
assertType(CHAR);
return value.charValue;
}
double getDouble() const {
assertType(DOUBLE);
return value.doubleValue;
}
float getFloat() const {
assertType(FLOAT);
return value.floatValue;
}
int getInt() const {
assertType(INT);
return value.intValue;
}
int getJavaObjectId() const {
assertType(JAVA_OBJECT);
return value.intValue;
}
int getJsObjectId() const {
assertType(JS_OBJECT);
return value.intValue;
}
int64_t getLong() const {
assertType(LONG);
return value.longValue;
}
short getShort() const {
assertType(SHORT);
return value.shortValue;
}
const std::string getString() const {
assertType(STRING);
return std::string(*value.stringValue);
}
ValueType getType() const {
return type;
}
bool isBoolean() const {
return type == BOOLEAN;
}
bool isByte() const {
return type == BYTE;
}
bool isChar() const {
return type == CHAR;
}
bool isDouble() const {
return type == DOUBLE;
}
bool isFloat() const {
return type == FLOAT;
}
bool isInt() const {
return type == INT;
}
bool isJavaObject() const {
return type == JAVA_OBJECT;
}
bool isJsObject() const {
return type == JS_OBJECT;
}
bool isLong() const {
return type == LONG;
}
bool isNull() const {
return type == NULL_TYPE;
}
bool isNumber() const {
switch (type) {
case BYTE:
case CHAR:
case DOUBLE:
case FLOAT:
case INT:
case LONG:
case SHORT:
return true;
default:
return false;
}
}
bool isPrimitive() const {
switch (type) {
case BOOLEAN:
case BYTE:
case CHAR:
case DOUBLE:
case FLOAT:
case INT:
case LONG:
case SHORT:
return true;
default:
return false;
}
}
bool isShort() const {
return type == SHORT;
}
bool isString() const {
return type == STRING;
}
bool isUndefined() const {
return type == UNDEFINED;
}
void setBoolean(bool val) {
clearOldValue();
type = BOOLEAN;
value.boolValue = val;
}
void setByte(unsigned char val) {
clearOldValue();
type = BYTE;
value.byteValue = val;
}
void setChar(unsigned short val) {
clearOldValue();
type = CHAR;
value.charValue = val;
}
void setDouble(double val) {
clearOldValue();
type = DOUBLE;
value.doubleValue = val;
}
void setFloat(float val) {
clearOldValue();
type = FLOAT;
value.floatValue = val;
}
void setInt(int val) {
clearOldValue();
type = INT;
value.intValue = val;
}
void setJavaObject(int objectId) {
clearOldValue();
type = JAVA_OBJECT;
value.intValue = objectId;
}
void setJsObjectId(int val) {
clearOldValue();
type = JS_OBJECT;
value.intValue = val;
}
void setLong(int64_t val) {
clearOldValue();
type = LONG;
value.longValue = val;
}
void setNull() {
clearOldValue();
type = NULL_TYPE;
}
void setShort(short val) {
clearOldValue();
type = SHORT;
value.shortValue = val;
}
void setString(const char* chars, int len) {
setString(std::string(chars, len));
}
void setString(const std::string& val) {
clearOldValue();
type = STRING;
value.stringValue = new std::string(val);
}
void setUndefined() {
clearOldValue();
type = UNDEFINED;
}
std::string toString() const {
char buf[64];
switch (type) {
case NULL_TYPE:
return "null";
case BOOLEAN:
snprintf(buf, sizeof(buf), "boolean(%s)", getBoolean() ? "true"
: "false");
return std::string(buf);
case BYTE:
snprintf(buf, sizeof(buf), "byte(%d)", getByte());
return std::string(buf);
case CHAR:
snprintf(buf, sizeof(buf), "char(%d)", getChar());
return std::string(buf);
case SHORT:
snprintf(buf, sizeof(buf), "short(%d)", getShort());
return std::string(buf);
case INT:
snprintf(buf, sizeof(buf), "int(%d)", getInt());
return std::string(buf);
case LONG:
snprintf(buf, sizeof(buf), "long(%lld)",
static_cast<long long>(getLong()));
return std::string(buf);
case FLOAT:
snprintf(buf, sizeof(buf), "float(%g)", getFloat());
return std::string(buf);
case DOUBLE:
snprintf(buf, sizeof(buf), "double(%g)", getDouble());
return std::string(buf);
case STRING:
snprintf(buf, sizeof(buf), "string(%.20s)", getString().c_str());
return std::string(buf);
case JAVA_OBJECT:
snprintf(buf, sizeof(buf), "JavaObj(%d)", getJavaObjectId());
return std::string(buf);
case JS_OBJECT:
snprintf(buf, sizeof(buf), "JsObj(%d)", getJsObjectId());
return std::string(buf);
case UNDEFINED:
return "undefined";
default:
return "Unknown type";
}
}
private:
void assertType(ValueType reqType) const {
if (type != reqType) {
Debug::log(Debug::Error) << "Value::assertType - expecting type "
<< int(reqType) << ", was " << int(type) << Debug::flush;
// TODO(jat): is this portable? Should we do something else here?
abort();
}
}
void clearOldValue() {
if (type == STRING) {
delete value.stringValue;
type = UNDEFINED;
}
}
// Precondition: existing value, if any, has been cleared
void copyValue(const Value& other) {
type = other.type;
value = other.value;
// handle deep copies of value types that need it
switch (type) {
case STRING:
value.stringValue = new std::string(*value.stringValue);
break;
default:
// no other values need deep copies
break;
}
}
};
inline Debug::DebugStream& operator<<(Debug::DebugStream& dbg, const Value& val) {
if (dbg.isActive()) {
dbg << val.toString();
}
return dbg;
}
#endif