summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2014-12-02 14:59:17 +0100
committerAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2014-12-02 14:59:17 +0100
commit0c26390e71193947a67bdd0536915523da38f00f (patch)
tree028135ee3c3c202ae5220f41d4a01600fb86a379
parent5554f3594d00e267af447a24149f655ceff64d17 (diff)
added revamped variant type
-rw-r--r--CMakeLists.txt33
-rw-r--r--src/core/variant/Variant.cpp58
-rw-r--r--src/core/variant/Variant.hpp624
3 files changed, 699 insertions, 16 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 327f664..3a52b6e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -112,10 +112,11 @@ ADD_LIBRARY(ousia_core
src/core/parser/Parser
src/core/parser/ParserStack
src/core/parser/Scope
- src/core/script/Function
- src/core/script/Object
- src/core/script/ScriptEngine
- src/core/script/Variant
+# src/core/script/Function
+# src/core/script/Object
+# src/core/script/ScriptEngine
+# src/core/script/Variant
+ src/core/variant/Variant
)
# ousia_xml library
@@ -159,9 +160,9 @@ IF(TEST)
test/core/TokenizerTest
test/core/UtilsTest
test/core/parser/ParserStackTest
- test/core/script/FunctionTest
- test/core/script/ObjectTest
- test/core/script/VariantTest
+# test/core/script/FunctionTest
+# test/core/script/ObjectTest
+# test/core/script/VariantTest
)
TARGET_LINK_LIBRARIES(ousia_test_core
@@ -179,19 +180,19 @@ IF(TEST)
ousia_xml
)
- ADD_EXECUTABLE(ousia_test_mozjs
- test/plugins/mozjs/MozJsScriptEngineTest
- )
+# ADD_EXECUTABLE(ousia_test_mozjs
+# test/plugins/mozjs/MozJsScriptEngineTest
+# )
- TARGET_LINK_LIBRARIES(ousia_test_mozjs
- ${GTEST_LIBRARIES}
- ousia_core
- ousia_mozjs
- )
+# TARGET_LINK_LIBRARIES(ousia_test_mozjs
+# ${GTEST_LIBRARIES}
+# ousia_core
+# ousia_mozjs
+# )
# Register the unit tests
ADD_TEST(ousia_test_core ousia_test_core)
ADD_TEST(ousia_test_xml ousia_test_xml)
- ADD_TEST(ousia_test_mozjs ousia_test_mozjs)
+# ADD_TEST(ousia_test_mozjs ousia_test_mozjs)
ENDIF()
diff --git a/src/core/variant/Variant.cpp b/src/core/variant/Variant.cpp
new file mode 100644
index 0000000..c86905c
--- /dev/null
+++ b/src/core/variant/Variant.cpp
@@ -0,0 +1,58 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "Variant.hpp"
+
+namespace ousia {
+
+/* Class Variant */
+
+const char *Variant::getTypeName(Type type)
+{
+ switch (type) {
+ case Type::NULLPTR:
+ return "null";
+ case Type::BOOL:
+ return "boolean";
+ case Type::INT:
+ return "integer";
+ case Type::DOUBLE:
+ return "number";
+ case Type::STRING:
+ return "string";
+ case Type::ARRAY:
+ return "array";
+ case Type::MAP:
+ return "map";
+ }
+ return "unknown";
+}
+
+/* Class VariantTypeException */
+
+Variant::TypeException::TypeException(Type actualType, Type requestedType)
+ : OusiaException(std::string("Variant: Requested \"") +
+ Variant::getTypeName(actualType) +
+ std::string("\" but is \"") +
+ Variant::getTypeName(requestedType) + std::string("\"")),
+ actualType(actualType),
+ requestedType(requestedType)
+{
+}
+}
+
diff --git a/src/core/variant/Variant.hpp b/src/core/variant/Variant.hpp
new file mode 100644
index 0000000..26b053a
--- /dev/null
+++ b/src/core/variant/Variant.hpp
@@ -0,0 +1,624 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file Variant.hpp
+ *
+ * The Variant class is used to efficiently represent a variables of varying
+ * type. Variant instances are used to represent user data and to exchange
+ * information between the host application and the script clients.
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+#ifndef _OUSIA_VARIANT_HPP_
+#define _OUSIA_VARIANT_HPP_
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include <vector>
+
+// TODO: Use
+// http://nikic.github.io/2012/02/02/Pointer-magic-for-efficient-dynamic-value-representations.html
+// later (will allow to use 8 bytes for a variant)
+
+#include <core/Exceptions.hpp>
+
+namespace ousia {
+
+/**
+ * Instances of the Variant class represent any kind of data that is exchanged
+ * between the host application and the script engine. Variants are immutable.
+ */
+class Variant {
+public:
+ /**
+ * Enum containing the possible types a variant may have.
+ */
+ enum class Type : int16_t {
+ NULLPTR,
+ BOOL,
+ INT,
+ DOUBLE,
+ STRING,
+ ARRAY,
+ MAP
+ };
+
+ /**
+ * Exception thrown whenever a variant is accessed via a getter function
+ * that
+ * is not supported for the current variant type.
+ */
+ class TypeException : public OusiaException {
+ private:
+ /**
+ * Internally used string holding the exception message.
+ */
+ const std::string msg;
+
+ public:
+ /**
+ * Contains the actual type of the variant.
+ */
+ const Type actualType;
+
+ /**
+ * Contains the requested type of the variant.
+ */
+ const Type requestedType;
+
+ /**
+ * Constructor of the TypeException.
+ *
+ * @param actualType describes the actual type of the variant.
+ * @param requestedType describes the type in which the variant was
+ * requested.
+ */
+ TypeException(Type actualType, Type requestedType);
+ };
+
+ using boolType = bool;
+ using intType = int32_t;
+ using doubleType = double;
+ using stringType = std::string;
+ using arrayType = std::vector<Variant>;
+ using mapType = std::map<std::string, Variant>;
+
+private:
+ /**
+ * Used to store the actual type of the variant.
+ */
+ Type type = Type::NULLPTR;
+
+ /**
+ * Anonymous union containing the possible value of the variant.
+ */
+ union {
+ /**
+ * The boolean value. Only valid if type is Type::BOOL.
+ */
+ boolType boolVal;
+ /**
+ * The integer value. Only valid if type is Type::INT.
+ */
+ intType intVal;
+ /**
+ * The number value. Only valid if type is Type::DOUBLE.
+ */
+ doubleType doubleVal;
+ /**
+ * Pointer to the more complex data structures on the free store. Only
+ * valid if type is one of Type::STRING, Type::ARRAY,
+ * Type::MAP.
+ */
+ void *ptrVal = nullptr;
+ };
+
+ /**
+ * Internally used to convert the current pointer value to a reference of
+ * the specified type.
+ */
+ template <typename T>
+ T &asObj(Type requestedType) const
+ {
+ const Type actualType = getType();
+ if (actualType == requestedType) {
+ return *(static_cast<T *>(ptrVal));
+ }
+ throw TypeException{actualType, requestedType};
+ }
+
+ /**
+ * Used internally to assign the value of another Variant instance to this
+ * instance.
+ *
+ * @param v is the Variant instance that should be copied to this instance.
+ */
+ void copy(const Variant &v)
+ {
+ type = v.type;
+ switch (type) {
+ case Type::NULLPTR:
+ break;
+ case Type::BOOL:
+ boolVal = v.boolVal;
+ break;
+ case Type::INT:
+ intVal = v.intVal;
+ break;
+ case Type::DOUBLE:
+ doubleVal = v.doubleVal;
+ break;
+ case Type::STRING:
+ ptrVal = new stringType{v.asString()};
+ break;
+ case Type::ARRAY:
+ ptrVal = new arrayType{v.asArray()};
+ break;
+ case Type::MAP:
+ ptrVal = new mapType{v.asMap()};
+ break;
+ }
+ }
+
+ /**
+ * Used internally to move the value of another Variant instance to this
+ * instance.
+ *
+ * @param v is the Variant instance that should be copied to this instance.
+ */
+ void move(Variant &&v)
+ {
+ type = v.type;
+ switch (type) {
+ case Type::NULLPTR:
+ break;
+ case Type::BOOL:
+ boolVal = v.boolVal;
+ break;
+ case Type::INT:
+ intVal = v.intVal;
+ break;
+ case Type::DOUBLE:
+ doubleVal = v.doubleVal;
+ break;
+ case Type::STRING:
+ case Type::ARRAY:
+ case Type::MAP:
+ ptrVal = v.ptrVal;
+ v.ptrVal = nullptr;
+ break;
+ }
+ v.type = Type::NULLPTR;
+ }
+
+ /**
+ * Used internally to destroy any value that was allocated on the heap.
+ */
+ void destroy()
+ {
+ if (ptrVal) {
+ switch (type) {
+ case Type::STRING:
+ delete static_cast<stringType *>(ptrVal);
+ break;
+ case Type::ARRAY:
+ delete static_cast<arrayType *>(ptrVal);
+ break;
+ case Type::MAP:
+ delete static_cast<mapType *>(ptrVal);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+public:
+ /**
+ * Copy constructor of the Variant class.
+ *
+ * @param v is the Variant instance that should be cloned.
+ */
+ Variant(const Variant &v) { copy(v); }
+
+ /**
+ * Move constructor of the Variant class.
+ *
+ * @param v is the reference to the Variant instance that should be moved,
+ * this instance is invalidated afterwards.
+ */
+ Variant(Variant &&v) { move(std::move(v)); }
+
+ /**
+ * Default constructor. Type is set to Type:null.
+ */
+ Variant() { setNull(); }
+
+ /**
+ * Default destructor, frees any memory that was allocated on the heap.
+ */
+ ~Variant() { destroy(); }
+
+ /**
+ * Constructor for boolean values.
+ *
+ * @param b boolean value.
+ */
+ Variant(boolType b) { setBool(b); }
+
+ /**
+ * Constructor for integer values.
+ *
+ * @param i integer value.
+ */
+ Variant(intType i) { setInt(i); }
+
+ /**
+ * Constructor for double values.
+ *
+ * @param d double value.
+ */
+ Variant(doubleType d) { setDouble(d); }
+
+ /**
+ * Constructor for string values. The given string is copied and managed by
+ * the new Variant instance.
+ *
+ * @param s is a reference to a C-Style string used as string value.
+ */
+ Variant(const char *s) { setString(s); }
+
+ /**
+ * Constructor for array values. The given array is copied and managed by
+ * the new Variant instance.
+ *
+ * @param a is a reference to the array
+ */
+ Variant(std::vector<Variant> a) { setArray(std::move(a)); }
+
+ /**
+ * Constructor for map values. The given map is copied and managed by the
+ * new Variant instance.
+ *
+ * @param m is a reference to the map.
+ */
+ Variant(std::map<std::string, Variant> m) { setMap(std::move(m)); }
+
+ /**
+ * Copy assignment operator.
+ */
+ Variant &operator=(const Variant &v)
+ {
+ copy(v);
+ return *this;
+ }
+
+ /**
+ * Move assignment operator.
+ */
+ Variant &operator=(Variant &&v)
+ {
+ move(std::move(v));
+ return *this;
+ }
+
+ /**
+ * Assign nullptr_t operator (allows to write Variant v = nullptr).
+ *
+ * @param p is an instance of std::nullptr_t.
+ */
+ Variant &operator=(std::nullptr_t)
+ {
+ setNull();
+ return *this;
+ }
+
+ /**
+ * Assign a boolean value.
+ *
+ * @param b is the boolean value to which the variant should be set.
+ */
+ Variant &operator=(boolType b)
+ {
+ setBool(b);
+ return *this;
+ }
+
+ /**
+ * Assign an integer value.
+ *
+ * @param i is the integer value to which the variant should be set.
+ */
+ Variant &operator=(intType i)
+ {
+ setInt(i);
+ return *this;
+ }
+
+ /**
+ * Assign a double value.
+ *
+ * @param i is the integer value to which the variant should be set.
+ */
+ Variant &operator=(doubleType d)
+ {
+ setInt(d);
+ return *this;
+ }
+
+ /**
+ * Checks whether this Variant instance represents the nullptr.
+ *
+ * @return true if the Variant instance represents the nullptr, false
+ * otherwise.
+ */
+ bool isNull() const { return type == Type::NULLPTR; }
+
+ /**
+ * Checks whether this Variant instance is a boolean.
+ *
+ * @return true if the Variant instance is a boolean, false otherwise.
+ */
+ bool isBool() const { return type == Type::BOOL; }
+
+ /**
+ * Checks whether this Variant instance is an integer.
+ *
+ * @return true if the Variant instance is an integer, false otherwise.
+ */
+ bool isInt() const { return type == Type::INT; }
+
+ /**
+ * Checks whether this Variant instance is a double.
+ *
+ * @return true if the Variant instance is a double, false otherwise.
+ */
+ bool isDouble() const { return type == Type::DOUBLE; }
+
+ /**
+ * Checks whether this Variant instance is a string.
+ *
+ * @return true if the Variant instance is a string, false otherwise.
+ */
+ bool isString() const { return type == Type::STRING; }
+
+ /**
+ * Checks whether this Variant instance is an array.
+ *
+ * @return true if the Variant instance is an array, false otherwise.
+ */
+ bool isArray() const { return type == Type::ARRAY; }
+
+ /**
+ * Checks whether this Variant instance is a map.
+ *
+ * @return true if the Variant instance is a map, false otherwise.
+ */
+ bool isMap() const { return type == Type::MAP; }
+
+ /**
+ * Returns the Variant boolean value. Performs no type conversion. Throws an
+ * exception if the underlying type is not a boolean.
+ *
+ * @return the boolean value.
+ */
+ boolType asBool() const
+ {
+ if (isBool()) {
+ return boolVal;
+ }
+ throw TypeException{getType(), Type::BOOL};
+ }
+
+ /**
+ * Returns the Variant integer value. Performs no type conversion. Throws an
+ * exception if the underlying type is not an integer.
+ *
+ * @return the integer value.
+ */
+ intType asInt() const
+ {
+ if (isInt()) {
+ return intVal;
+ }
+ throw TypeException{getType(), Type::INT};
+ }
+
+ /**
+ * Returns the Variant double value. Performs no type conversion. Throws an
+ * exception if the underlying type is not a double.
+ *
+ * @return the double value.
+ */
+ doubleType asDouble() const
+ {
+ if (isDouble()) {
+ return doubleVal;
+ }
+ throw TypeException{getType(), Type::DOUBLE};
+ }
+
+ /**
+ * Returns a const reference to the string value. Performs no type
+ * conversion. Throws an exception if the underlying type is not a string.
+ *
+ * @return the string value as const reference.
+ */
+ const stringType &asString() const
+ {
+ return asObj<stringType>(Type::STRING);
+ }
+
+ /**
+ * Returns a const reference to the string value. Performs no type
+ * conversion. Throws an exception if the underlying type is not a string.
+ *
+ * @return the string value as reference.
+ */
+ stringType &asString() { return asObj<stringType>(Type::STRING); }
+
+ /**
+ * Returns a const reference to the array value. Performs no type
+ * conversion. Throws an exception if the underlying type is not an array.
+ *
+ * @return the array value as const reference.
+ */
+ const arrayType &asArray() const { return asObj<arrayType>(Type::ARRAY); }
+
+ /**
+ * Returns a const reference to the array value. Performs no type
+ * conversion. Throws an exception if the underlying type is not an array.
+ *
+ * @return the array value as reference.
+ */
+ arrayType &asArray() { return asObj<arrayType>(Type::ARRAY); }
+
+ /**
+ * Returns a const reference to the map value. Performs no type
+ * conversion. Throws an exception if the underlying type is not a map.
+ *
+ * @return the map value as const reference.
+ */
+ const mapType &asMap() const { return asObj<mapType>(Type::MAP); }
+
+ /**
+ * Returns a reference to the map value. Performs no type conversion.
+ * Throws an exception if the underlying type is not a map.
+ *
+ * @return the map value as reference.
+ */
+ mapType &asMap() { return asObj<mapType>(Type::MAP); }
+
+ /**
+ * Sets the variant to null.
+ */
+ void setNull()
+ {
+ destroy();
+ type = Type::NULLPTR;
+ ptrVal = nullptr;
+ }
+
+ /**
+ * Sets the variant to the given boolean value.
+ *
+ * @param b is the new boolean value.
+ */
+ void setBool(boolType b)
+ {
+ destroy();
+ type = Type::BOOL;
+ boolVal = b;
+ }
+
+ /**
+ * Sets the variant to the given integer value.
+ *
+ * @param i is the new integer value.
+ */
+ void setInt(intType i)
+ {
+ destroy();
+ type = Type::INT;
+ intVal = i;
+ }
+
+ /**
+ * Sets the variant to the given double value.
+ *
+ * @param d is the new double value.
+ */
+ void setDouble(doubleType d)
+ {
+ destroy();
+ type = Type::DOUBLE;
+ doubleVal = d;
+ }
+
+ /**
+ * Sets the variant to the given string value.
+ *
+ * @param d is the new string value.
+ */
+ void setString(const char *s)
+ {
+ if (isString()) {
+ asString().assign(s);
+ } else {
+ destroy();
+ type = Type::STRING;
+ ptrVal = new stringType{s};
+ }
+ }
+
+ /**
+ * Sets the variant to the given array value.
+ *
+ * @param a is the new array value.
+ */
+ void setArray(arrayType a)
+ {
+ if (isArray()) {
+ asArray().swap(a);
+ } else {
+ destroy();
+ type = Type::ARRAY;
+ ptrVal = new arrayType{std::move(a)};
+ }
+ }
+
+ /**
+ * Sets the variant to the given map value.
+ *
+ * @param a is the new map value.
+ */
+ void setMap(mapType m)
+ {
+ if (isMap()) {
+ asMap().swap(m);
+ } else {
+ destroy();
+ type = Type::MAP;
+ ptrVal = new mapType{std::move(m)};
+ }
+ }
+
+ /**
+ * Returns the current type of the Variant.
+ *
+ * @return the current type of the Variant.
+ */
+ Type getType() const { return type; }
+
+ /**
+ * Returns the name of the given variant type as C-style string.
+ */
+ static const char *getTypeName(Type type);
+
+ /**
+ * Returns the name of the type of this variant instance.
+ */
+ const char *getTypeName() { return Variant::getTypeName(getType()); }
+};
+}
+
+#endif /* _OUSIA_VARIANT_HPP_ */
+