|  | #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 |