diff options
author | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-01-11 01:03:07 +0100 |
---|---|---|
committer | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-01-11 01:03:07 +0100 |
commit | 7950e05b381308a3beb3c6d1538de6af047e5c0c (patch) | |
tree | 70177ad76b5cdae74d551ed03e4acec939edd501 /src/core/common | |
parent | c204e8dc7e0d4f1317747d5f7f2e17aab449de1a (diff) |
Refactored conversion routines used in the Typesystem class and the Variant class into an own class, implemented missing conversion from string to integer/double, implemented proper JSON serialization of variants
Diffstat (limited to 'src/core/common')
-rw-r--r-- | src/core/common/Variant.cpp | 204 | ||||
-rw-r--r-- | src/core/common/Variant.hpp | 99 | ||||
-rw-r--r-- | src/core/common/VariantConverter.cpp | 255 | ||||
-rw-r--r-- | src/core/common/VariantConverter.hpp | 72 | ||||
-rw-r--r-- | src/core/common/VariantWriter.cpp | 165 | ||||
-rw-r--r-- | src/core/common/VariantWriter.hpp | 57 |
6 files changed, 670 insertions, 182 deletions
diff --git a/src/core/common/Variant.cpp b/src/core/common/Variant.cpp index e216aa1..b1a65ea 100644 --- a/src/core/common/Variant.cpp +++ b/src/core/common/Variant.cpp @@ -20,8 +20,11 @@ #include <core/managed/Managed.hpp> +#include "Logger.hpp" #include "Utils.hpp" #include "Variant.hpp" +#include "VariantConverter.hpp" +#include "VariantWriter.hpp" namespace ousia { @@ -68,115 +71,124 @@ const char *Variant::getTypeName(Type type) Variant::boolType Variant::toBool() const { - switch (getType()) { - case Type::NULLPTR: - return false; - case Type::BOOL: - return asBool(); - case Type::INT: - return asInt() != 0; - case Type::DOUBLE: - return asDouble() != 0.0; - default: - return true; - } - return false; + ExceptionLogger logger; + Variant res{*this}; + VariantConverter::toBool(res, logger, VariantConverter::Mode::ALL); + return res.asBool(); } Variant::intType Variant::toInt() const { - switch (getType()) { - case Type::NULLPTR: - return 0; - case Type::BOOL: - return asBool() ? 1 : 0; - case Type::INT: - return asInt(); - case Type::DOUBLE: - return asDouble(); - case Type::STRING: - case Type::MAGIC: - return 0; // TODO: Parse string as int - case Type::ARRAY: { - // JavaScript behaviour when converting arrays to ints - const arrayType &a = asArray(); - return (a.size() == 1) ? a[0].toInt() : 0; - } - default: - return 0; - } - return false; + ExceptionLogger logger; + Variant res{*this}; + VariantConverter::toInt(res, logger, VariantConverter::Mode::ALL); + return res.asInt(); } Variant::doubleType Variant::toDouble() const { - switch (getType()) { - case Type::NULLPTR: - return 0.0; - case Type::BOOL: - return asBool() ? 1.0 : 0.0; - case Type::INT: - return asInt(); - case Type::DOUBLE: - return asDouble(); - case Type::STRING: - case Type::MAGIC: - return 0.0; // TODO: Parse string as double - case Type::ARRAY: { - // JavaScript behaviour when converting array to doubles - const arrayType &a = asArray(); - return (a.size() == 1) ? a[0].toDouble() : 0; - } - default: - return 0.0; - } - return false; + ExceptionLogger logger; + Variant res{*this}; + VariantConverter::toDouble(res, logger, VariantConverter::Mode::ALL); + return res.asDouble(); } Variant::stringType Variant::toString(bool escape) const { - switch (getType()) { - case Type::NULLPTR: - return "null"; - case Type::BOOL: - return asBool() ? "true" : "false"; - case Type::INT: { - std::stringstream ss; - ss << asInt(); - return ss.str(); - } - case Type::DOUBLE: { - std::stringstream ss; - ss << asDouble(); - return ss.str(); - } - case Type::STRING: { - case Type::MAGIC: - // TODO: Use proper serialization function - if (escape) { - std::stringstream ss; - ss << "\"" << asString() << "\""; - return ss.str(); - } else { - return asString(); - } - } - case Type::ARRAY: - return Utils::join(asArray(), ", ", "[", "]"); - case Type::MAP: - return Utils::join(asMap(), ", ", "{", "}"); - case Type::OBJECT: { - std::stringstream ss; - ss << "<object " << ptrVal << ">"; - return ss.str(); - } - case Type::FUNCTION: { - std::stringstream ss; - ss << "<function " << static_cast<functionType*>(ptrVal)->get() << ">"; - return ss.str(); - } + ExceptionLogger logger; + Variant res{*this}; + VariantConverter::toString(res, logger, VariantConverter::Mode::ALL); + return res.asString(); +} + +/* Output stream operators */ + +std::ostream &operator<<(std::ostream &os, const Variant &v) +{ + VariantWriter::writeJson(v, os, true); + return os; +} + +/* Comparison operators */ + +bool operator<(const Variant &lhs, const Variant &rhs) +{ + // If the types do not match, we can not do a meaningful comparison. + if (lhs.getType() != rhs.getType()) { + throw Variant::TypeException(lhs.getType(), rhs.getType()); + } + switch (lhs.getType()) { + case Variant::Type::NULLPTR: + return false; + case Variant::Type::BOOL: + return lhs.boolVal < rhs.boolVal; + case Variant::Type::INT: + return lhs.intVal < rhs.intVal; + case Variant::Type::DOUBLE: + return lhs.doubleVal < rhs.doubleVal; + case Variant::Type::MAGIC: + case Variant::Type::STRING: + return lhs.asString() < rhs.asString(); + case Variant::Type::ARRAY: + return lhs.asArray() < rhs.asArray(); + case Variant::Type::MAP: + return lhs.asMap() < rhs.asMap(); + case Variant::Type::OBJECT: + return lhs.asObject().get() < rhs.asObject().get(); + case Variant::Type::FUNCTION: + return lhs.asFunction() < rhs.asFunction(); + } + throw OusiaException("Internal Error! Unknown type!"); +} + +bool operator>(const Variant &lhs, const Variant &rhs) +{ + return rhs < lhs; +} + +bool operator<=(const Variant &lhs, const Variant &rhs) +{ + return !(lhs > rhs); +} + +bool operator>=(const Variant &lhs, const Variant &rhs) +{ + return !(lhs < rhs); +} + +bool operator==(const Variant &lhs, const Variant &rhs) +{ + if (lhs.getType() != rhs.getType()) { + return false; + } + switch (lhs.getType()) { + case Variant::Type::NULLPTR: + return true; + case Variant::Type::BOOL: + return lhs.boolVal == rhs.boolVal; + case Variant::Type::INT: + return lhs.intVal == rhs.intVal; + case Variant::Type::DOUBLE: + return lhs.doubleVal == rhs.doubleVal; + case Variant::Type::STRING: + case Variant::Type::MAGIC: + return lhs.asString() == rhs.asString(); + case Variant::Type::ARRAY: + return lhs.asArray() == rhs.asArray(); + case Variant::Type::MAP: + return lhs.asMap() == rhs.asMap(); + case Variant::Type::OBJECT: + return lhs.asObject() == rhs.asObject(); + case Variant::Type::FUNCTION: + return lhs.asFunction() == rhs.asFunction(); } - return ""; + throw OusiaException("Internal Error! Unknown type!"); } + +bool operator!=(const Variant &lhs, const Variant &rhs) +{ + return !(lhs == rhs); +} + } diff --git a/src/core/common/Variant.hpp b/src/core/common/Variant.hpp index 9c061c1..254e748 100644 --- a/src/core/common/Variant.hpp +++ b/src/core/common/Variant.hpp @@ -864,23 +864,17 @@ public: */ const char *getTypeName() { return Variant::getTypeName(getType()); } - /** - * Prints the Variant to the output stream. + /* + * Output stream operator. */ - friend std::ostream &operator<<(std::ostream &os, const Variant &v) - { - return os << v.toString(true); - } /** - * Prints a key value pair to the output stream. + * Prints the Variant to the output stream as JSON data. + * + * @param os is the output stream the variant should be written to. + * @param v is the variant that should be written to the output stream. */ - friend std::ostream &operator<<(std::ostream &os, - const mapType::value_type &v) - { - // TODO: Use proper serialization function - return os << "\"" << v.first << "\": " << v.second.toString(true); - } + friend std::ostream &operator<<(std::ostream &os, const Variant &v); /* * Comprison operators. @@ -895,35 +889,7 @@ public: * @param rhs is the right hand side of the comparison. * @return true if lhs is smaller than rhs. */ - friend bool operator<(const Variant &lhs, const Variant &rhs) - { - // If the types do not match, we can not do a meaningful comparison. - if (lhs.getType() != rhs.getType()) { - throw TypeException(lhs.getType(), rhs.getType()); - } - switch (lhs.getType()) { - case Type::NULLPTR: - return false; - case Type::BOOL: - return lhs.boolVal < rhs.boolVal; - case Type::INT: - return lhs.intVal < rhs.intVal; - case Type::DOUBLE: - return lhs.doubleVal < rhs.doubleVal; - case Type::MAGIC: - case Type::STRING: - return lhs.asString() < rhs.asString(); - case Type::ARRAY: - return lhs.asArray() < rhs.asArray(); - case Type::MAP: - return lhs.asMap() < rhs.asMap(); - case Type::OBJECT: - return lhs.asObject().get() < rhs.asObject().get(); - case Type::FUNCTION: - return lhs.asFunction() < rhs.asFunction(); - } - throw OusiaException("Internal Error! Unknown type!"); - } + friend bool operator<(const Variant &lhs, const Variant &rhs); /** * Returns true if the given left hand side is larger than the right hand @@ -934,10 +900,7 @@ public: * @param rhs is the right hand side of the comparison. * @return true if lhs is larger than rhs. */ - friend bool operator>(const Variant &lhs, const Variant &rhs) - { - return rhs < lhs; - } + friend bool operator>(const Variant &lhs, const Variant &rhs); /** * Returns true if the given left hand side is smaller or equal to the @@ -948,10 +911,7 @@ public: * @param rhs is the right hand side of the comparison. * @return true if lhs is smaller than or equal to rhs. */ - friend bool operator<=(const Variant &lhs, const Variant &rhs) - { - return !(lhs > rhs); - } + friend bool operator<=(const Variant &lhs, const Variant &rhs); /** * Returns true if the given left hand side is larger or equal to the @@ -962,10 +922,7 @@ public: * @param rhs is the right hand side of the comparison. * @return true if lhs is larger than or equal to rhs. */ - friend bool operator>=(const Variant &lhs, const Variant &rhs) - { - return !(lhs < rhs); - } + friend bool operator>=(const Variant &lhs, const Variant &rhs); /** * Returns true if the given left hand side and right hand side are equal. @@ -976,34 +933,7 @@ public: * @param rhs is the right hand side of the comparison. * @return true if lhs equals rhs. */ - friend bool operator==(const Variant &lhs, const Variant &rhs) - { - if (lhs.getType() != rhs.getType()) { - return false; - } - switch (lhs.getType()) { - case Type::NULLPTR: - return true; - case Type::BOOL: - return lhs.boolVal == rhs.boolVal; - case Type::INT: - return lhs.intVal == rhs.intVal; - case Type::DOUBLE: - return lhs.doubleVal == rhs.doubleVal; - case Type::STRING: - case Type::MAGIC: - return lhs.asString() == rhs.asString(); - case Type::ARRAY: - return lhs.asArray() == rhs.asArray(); - case Type::MAP: - return lhs.asMap() == rhs.asMap(); - case Type::OBJECT: - return lhs.asObject() == rhs.asObject(); - case Type::FUNCTION: - return lhs.asFunction() == rhs.asFunction(); - } - throw OusiaException("Internal Error! Unknown type!"); - } + friend bool operator==(const Variant &lhs, const Variant &rhs); /** * Returns true if the given left hand side are equal. Uses the comparison @@ -1014,10 +944,7 @@ public: * @param rhs is the right hand side of the comparison. * @return true if lhs is not equal to rhs. */ - friend bool operator!=(const Variant &lhs, const Variant &rhs) - { - return !(lhs == rhs); - } + friend bool operator!=(const Variant &lhs, const Variant &rhs); }; } diff --git a/src/core/common/VariantConverter.cpp b/src/core/common/VariantConverter.cpp new file mode 100644 index 0000000..f9d465e --- /dev/null +++ b/src/core/common/VariantConverter.cpp @@ -0,0 +1,255 @@ +/* + 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 <string> +#include <sstream> + +#include "Logger.hpp" +#include "Number.hpp" +#include "Rtti.hpp" +#include "Variant.hpp" +#include "VariantConverter.hpp" +#include "VariantWriter.hpp" + +namespace ousia { + +static std::string msgUnexpectedType(Variant::Type actualType, + Variant::Type requestedType) +{ + return std::string("Cannot convert ") + Variant::getTypeName(actualType) + + std::string(" to ") + Variant::getTypeName(requestedType); +} + +bool VariantConverter::toBool(Variant &var, Logger &logger, Mode mode) +{ + // Perform safe conversions + const Variant::Type type = var.getType(); + switch (type) { + case Variant::Type::BOOL: + // No conversion needed if "var" already is a boolean + return true; + default: + break; + } + + // Perform potentially dangerous conversions in the "ALL" mode + if (mode == Mode::ALL) { + switch (var.getType()) { + case Variant::Type::NULLPTR: + var = false; + return true; + case Variant::Type::INT: + var = var.asInt() != 0; + return true; + case Variant::Type::DOUBLE: + var = var.asDouble() != 0.0; + return true; + default: + var = true; + return true; + } + } + + // No conversion possible, assign default value and log error + logger.error(msgUnexpectedType(var.getType(), Variant::Type::BOOL)); + var = false; + return false; +} + +bool VariantConverter::toInt(Variant &var, Logger &logger, Mode mode) +{ + // Perform safe conversions + const Variant::Type type = var.getType(); + switch (type) { + case Variant::Type::INT: + // No conversion needed if "var" already is an integer + return true; + default: + break; + } + + // Perform all potentially dangerous conversions in the "ALL" mode + if (mode == Mode::ALL) { + switch (type) { + case Variant::Type::NULLPTR: + var = 0; + return true; + case Variant::Type::BOOL: + var = var.asBool() ? 1 : 0; + return true; + case Variant::Type::DOUBLE: + var = (Variant::intType)var.asDouble(); + return true; + case Variant::Type::STRING: + case Variant::Type::MAGIC: { + Number n; + n.parse(var.asString(), logger); + if (n.isInt()) { + var = (Variant::intType)n.intValue(); + } else { + var = (Variant::doubleType)n.doubleValue(); + } + return true; + } + case Variant::Type::ARRAY: { + try { + // JavaScript behaviour when converting arrays to doubles + const Variant::arrayType &a = var.asArray(); + var = (a.size() == 1) ? a[0].toInt() : 0.0; + return true; + } + catch (LoggableException ex) { + logger.log(ex); + } + } + default: + break; + } + } + + // No conversion possible, assign default value and log error + logger.error(msgUnexpectedType(var.getType(), Variant::Type::INT)); + var = 0; + return false; +} + +bool VariantConverter::toDouble(Variant &var, Logger &logger, Mode mode) +{ + // Perform safe conversions + const Variant::Type type = var.getType(); + switch (type) { + case Variant::Type::DOUBLE: + // No conversion needed if "var" already is a double + return true; + case Variant::Type::INT: + // Converting integers to doubles is safe + var = (Variant::doubleType)var.asInt(); + return true; + default: + break; + } + + // Perform all potentially dangerous conversions in the "ALL" mode + if (mode == Mode::ALL) { + switch (type) { + case Variant::Type::NULLPTR: + var = 0.0; + return true; + case Variant::Type::BOOL: + var = var.asBool() ? 1.0 : 0.0; + return true; + case Variant::Type::STRING: + case Variant::Type::MAGIC: { + Number n; + n.parse(var.asString(), logger); + var = (Variant::doubleType)n.doubleValue(); + return true; + } + case Variant::Type::ARRAY: { + try { + // JavaScript behaviour when converting arrays to doubles + const Variant::arrayType &a = var.asArray(); + var = (a.size() == 1) ? a[0].toDouble() : 0.0; + return true; + } + catch (LoggableException ex) { + logger.log(ex); + } + } + default: + break; + } + } + + // No conversion possible, assign default value and log error + logger.error(msgUnexpectedType(var.getType(), Variant::Type::DOUBLE)); + var = 0.0; + return false; +} + +bool VariantConverter::toString(Variant &var, Logger &logger, Mode mode) +{ + // Perform safe conversions (all these operations are considered "lossless") + const Variant::Type type = var.getType(); + switch (type) { + case Variant::Type::NULLPTR: + var = "null"; + return true; + case Variant::Type::BOOL: + var = var.asBool() ? "true" : "false"; + return true; + case Variant::Type::INT: { + std::stringstream ss; + ss << var.asInt(); + var = ss.str().c_str(); + return true; + } + case Variant::Type::DOUBLE: { + std::stringstream ss; + ss << var.asDouble(); + var = ss.str().c_str(); + return true; + } + case Variant::Type::MAGIC: + case Variant::Type::STRING: + // No conversion needed if "var" already is a string (or a magic + // string value) + return true; + default: + break; + } + + // Perform lossy conversions + if (mode == Mode::ALL) { + switch (type) { + case Variant::Type::ARRAY: + case Variant::Type::MAP: { + std::stringstream ss; + VariantWriter::writeJson(var, ss, false); + var = ss.str().c_str(); + return true; + } + case Variant::Type::OBJECT: { + // Print object address and type + Variant::objectType obj = var.asObject(); + std::stringstream ss; + ss << "<object " << obj.get() << " (" << obj->type().name << ")" + << ">"; + var = ss.str().c_str(); + return true; + } + case Variant::Type::FUNCTION: { + // Print function pointer address + Variant::functionType obj = var.asFunction(); + std::stringstream ss; + ss << "<function " << obj.get() << ">"; + var = ss.str().c_str(); + return true; + } + default: + break; + } + } + + // No conversion possible, assign default value and log error + logger.error(msgUnexpectedType(var.getType(), Variant::Type::STRING)); + var = ""; + return false; +} +} + diff --git a/src/core/common/VariantConverter.hpp b/src/core/common/VariantConverter.hpp new file mode 100644 index 0000000..b683083 --- /dev/null +++ b/src/core/common/VariantConverter.hpp @@ -0,0 +1,72 @@ +/* + 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/>. +*/ + +#ifndef _OUSIA_VARIANT_CONVERTER_HPP_ +#define _OUSIA_VARIANT_CONVERTER_HPP_ + +namespace ousia { + +// Forward declaration +class Variant; +class Logger; + +/** + * The VariantConverter class is used to convert a variant to a certain + * prespecified type. The functions ensure that the variant has the requested + * type, even if the conversion fails. + */ +class VariantConverter { + +public: + /** + * Enumeration used to define the mode of conversion -- either only safe + * conversions (without any data loss) are performed, or all possible + * conversions are tried (with possible data loss). + */ + enum class Mode { + SAFE, ALL + }; + + /** + * Makes sure the given variant is a boolean. If the "mode" parameter is + * set to Mode::SAFE, only booleans can be converted to booleans. For all + * other types the conversion fails. If "mode" is set to Mode::ALL, nullptr + * values and zero numeric values are treated as "false", all other values + * are treated as "true". + * + * @param var is instance of the Variant class that should be converted to + * the requested type. + * @param logger is a reference to the logger instance into which messages + * should be logged. + * @param mode is the conversion mode. See method description for the exact + * effect. + */ + static bool toBool(Variant &var, Logger &logger, Mode mode = Mode::SAFE); + + static bool toInt(Variant &var, Logger &logger, Mode mode = Mode::SAFE); + + static bool toDouble(Variant &var, Logger &logger, Mode mode = Mode::SAFE); + + static bool toString(Variant &var, Logger &logger, Mode mode = Mode::SAFE); + +}; + +} + +#endif /* _OUSIA_VARIANT_CONVERTER_HPP_ */ + diff --git a/src/core/common/VariantWriter.cpp b/src/core/common/VariantWriter.cpp new file mode 100644 index 0000000..39dfc3b --- /dev/null +++ b/src/core/common/VariantWriter.cpp @@ -0,0 +1,165 @@ +/* + 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" +#include "VariantWriter.hpp" + +namespace ousia { + +/** + * Helper function used to write a JSON string, including quotation marks. + * + * @param str is the string that should be serialized. + * @param stream is the stream to which the JSON string should be written. + */ +static void writeJsonString(const std::string str, std::ostream &stream) +{ + stream << "\""; + for (char c : str) { + switch (c) { + case '\b': + stream << "\\b"; + break; + case '\f': + stream << "\\f"; + break; + case '\n': + stream << "\\n"; + break; + case '\r': + stream << "\\r"; + break; + case '\t': + stream << "\\t"; + break; + case '\v': + stream << "\\v"; + break; + case '\\': + stream << "\\"; + break; + case '"': + stream << "\\\""; + break; + default: + stream << c; + break; + } + } + stream << "\""; +} + +/** + * Helper function used to write the indentation, but only if the pretty mode + * is enabled. + * + * @param stream is the stream the result should be written to. + * @param pretty if false, no indentation is written. + */ +static void writeIndentation(std::ostream &stream, bool pretty, int level) +{ + if (pretty) { + for (int i = 0; i < level; i++) { + stream << "\t"; + } + } +} + +/** + * Helper function used to write a linebreak, but only if the pretty mode is + * enabled. + * + * @param stream is the stream the result should be written to. + * @param pretty if false, no linebreak is written. + */ +static void writeLinebreak(std::ostream &stream, bool pretty) +{ + if (pretty) { + stream << "\n"; + } +} + +/** + * Helper function used to serialize JSON with indentation. + * + * @param var is the variant that should be serialized. + * @param stream is the stream the result should be written to. + * @param pretty if true, the resulting value is properly indented. + * @param level is the current indentation level. + */ +static void writeJsonInternal(const Variant &var, std::ostream &stream, + bool pretty, int level) +{ + switch (var.getType()) { + case Variant::Type::NULLPTR: + case Variant::Type::BOOL: + case Variant::Type::INT: + case Variant::Type::DOUBLE: + case Variant::Type::FUNCTION: + case Variant::Type::OBJECT: + stream << var.toString(); + return; + case Variant::Type::STRING: + case Variant::Type::MAGIC: + writeJsonString(var.toString(), stream); + return; + case Variant::Type::ARRAY: { + stream << "["; + writeLinebreak(stream, pretty); + const Variant::arrayType &arr = var.asArray(); + for (size_t i = 0; i < arr.size(); i++) { + writeIndentation(stream, pretty, level + 1); + writeJsonInternal(arr[i], stream, pretty, level + 1); + if (i + 1 != arr.size()) { + stream << ","; + } + writeLinebreak(stream, pretty); + } + writeIndentation(stream, pretty, level); + stream << "]"; + return; + } + case Variant::Type::MAP: { + writeIndentation(stream, pretty, level); + stream << "{"; + writeLinebreak(stream, pretty); + const Variant::mapType &map = var.asMap(); + for (auto it = map.cbegin(); it != map.cend();) { + writeIndentation(stream, pretty, level + 1); + writeJsonString(it->first, stream); + stream << (pretty ? ": " : ":"); + writeJsonInternal(it->second, stream, pretty, level + 1); + if ((++it) != map.cend()) { + stream << ","; + } + writeLinebreak(stream, pretty); + } + writeIndentation(stream, pretty, level); + stream << "}"; + return; + } + } +} + +void VariantWriter::writeJson(const Variant &var, std::ostream &stream, + bool pretty) +{ + writeJsonInternal(var, stream, pretty, 0); +} +} + diff --git a/src/core/common/VariantWriter.hpp b/src/core/common/VariantWriter.hpp new file mode 100644 index 0000000..211da34 --- /dev/null +++ b/src/core/common/VariantWriter.hpp @@ -0,0 +1,57 @@ +/* + 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 VariantWriter.hpp + * + * Contains the VariantWriter class which provides serialization functions for + * Variant types. + * + * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) + */ + +#ifndef _OUSIA_VARIANT_WRITER_HPP_ +#define _OUSIA_VARIANT_WRITER_HPP_ + +#include <ostream> + +namespace ousia { + +// Forward declaration +class Variant; + +/** + * Class which provides serialization functions for writing variants to an + * output stream in various formats. + */ +class VariantWriter { +public: + /** + * Dumps the Variant as JSON data. + * + * @param var is the variant that should be serialized. + * @param stream is the stream the result should be written to. + * @param pretty if true, the resulting value is properly indented. + */ + static void writeJson(const Variant &var, std::ostream &stream, + bool pretty = true); +}; +} + +#endif /* _OUSIA_VARIANT_WRITER_HPP_ */ + |