| #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 setDouble(const 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 |