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