summaryrefslogtreecommitdiff
path: root/src/core/variant
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2014-12-11 15:26:50 +0100
committerAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2014-12-11 15:26:50 +0100
commit3f62168ed0b088eec3cb2903f03966f7d501f564 (patch)
tree781f5bd9b304d9eb931827a26f463575d772983d /src/core/variant
parentb74936760e28a92cadfaec47928ea478fe2d72ee (diff)
moved to CharReader everywhere
Diffstat (limited to 'src/core/variant')
-rw-r--r--src/core/variant/Reader.cpp624
-rw-r--r--src/core/variant/Reader.hpp169
-rw-r--r--src/core/variant/Variant.cpp155
-rw-r--r--src/core/variant/Variant.hpp766
4 files changed, 0 insertions, 1714 deletions
diff --git a/src/core/variant/Reader.cpp b/src/core/variant/Reader.cpp
deleted file mode 100644
index 5c167cd..0000000
--- a/src/core/variant/Reader.cpp
+++ /dev/null
@@ -1,624 +0,0 @@
-/*
- 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 <iostream>
-
-#include <cmath>
-#include <sstream>
-
-#include <core/Utils.hpp>
-
-#include "Reader.hpp"
-
-namespace ousia {
-namespace variant {
-
-// TODO: Better error messages (like "Expected 'x' but got 'y'")
-// TODO: Replace delims with single char delim where possible
-// TODO: Use custom return value instead of std::pair
-// TODO: Allow buffered char reader to "fork"
-// TODO: Rename CharReader to shorter CharReader
-// TODO: Implement context in CharReader (to allow error messages to extract the
-// current line)
-
-/* Error Messages */
-
-static const char *ERR_UNEXPECTED_CHAR = "Unexpected character";
-static const char *ERR_UNEXPECTED_END = "Unexpected literal end";
-static const char *ERR_UNTERMINATED = "Unterminated literal";
-static const char *ERR_INVALID_ESCAPE = "Invalid escape sequence";
-static const char *ERR_INVALID_INTEGER = "Invalid integer value";
-static const char *ERR_TOO_LARGE = "Value too large to represent";
-
-/* Class Number */
-
-/**
- * Class used internally to represent a number (integer or double). The number
- * is represented by its components (base value a, nominator n, denominator d,
- * exponent e, sign s and exponent sign sE).
- */
-class Number {
-private:
- /**
- * Reprsents the part of the number: Base value a, nominator n, exponent e.
- */
- enum class Part { A, N, E };
-
- /**
- * State used in the parser state machine
- */
- enum class State {
- INIT,
- HAS_MINUS,
- LEADING_ZERO,
- LEADING_POINT,
- INT,
- HEX,
- POINT,
- EXP_INIT,
- EXP_HAS_MINUS,
- EXP
- };
-
- /**
- * Returns the numeric value of the given ASCII character (returns 0 for
- * '0', 1 for '1', 10 for 'A' and so on).
- *
- * @param c is the character for which the numeric value should be returned.
- * @return the numeric value the character represents.
- */
- static int charValue(char c)
- {
- if (c >= '0' && c <= '9') {
- return c & 0x0F;
- }
- if ((c >= 'A' && c <= 'O') || (c >= 'a' && c <= 'o')) {
- return (c & 0x0F) + 9;
- }
- return -1;
- }
-
- /**
- * Appends the value of the character c to the internal number
- * representation and reports any errors that might occur.
- */
- bool appendChar(char c, int base, Part p, CharReader &reader,
- Logger &logger)
- {
- // Check whether the given character is valid
- int v = charValue(c);
- if (v < 0 || v >= base) {
- logger.errorAt(ERR_UNEXPECTED_CHAR, reader);
- return false;
- }
-
- // Append the number to the specified part
- switch (p) {
- case Part::A:
- a = a * base + v;
- break;
- case Part::N:
- n = n * base + v;
- d = d * base;
- break;
- case Part::E:
- e = e * base + v;
- break;
- }
-
- // Check for any overflows
- if (a < 0 || n < 0 || d < 0 || e < 0) {
- logger.errorAt(ERR_TOO_LARGE, reader);
- return false;
- }
- return true;
- }
-
-public:
- /**
- * Sign and exponent sign.
- */
- int8_t s, sE;
-
- /**
- * Exponent
- */
- int16_t e;
-
- /**
- * Base value, nominator, denominator
- */
- int64_t a, n, d;
-
- /**
- * Constructor of the number class.
- */
- Number() : s(1), sE(1), e(0), a(0), n(0), d(1) {}
-
- /**
- * Returns the represented double value.
- */
- double doubleValue()
- {
- return s * (a + ((double)n / (double)d)) * pow(10.0, (double)(sE * e));
- }
-
- /**
- * Returns the represented integer value. Only a lossless operation, if the
- * number is an integer (as can be checked via the isInt method), otherwise
- * the exponent and the fractional value will be truncated.
- */
- int64_t intValue() { return s * a; }
-
- /**
- * Returns true, if the number is an integer (has no fractional or
- * exponential part).
- */
- bool isInt() { return (n == 0) && (d == 1) && (e == 0); }
-
- /**
- * Tries to parse the number from the given stream and loggs any errors to
- * the given logger instance. Numbers are terminated by one of the given
- * delimiters.
- */
- bool parse(CharReader &reader, Logger &logger,
- const std::unordered_set<char> &delims)
- {
- State state = State::INIT;
- char c;
-
- // Consume the first whitespace characters
- reader.consumeWhitespace();
-
- // Iterate over the FSM to extract numbers
- while (reader.peek(c)) {
- // Abort, once a delimiter or whitespace is reached
- if (Utils::isWhitespace(c) || delims.count(c)) {
- reader.resetPeek();
- break;
- }
-
- // The character is not a whitespace character and not a delimiter
- switch (state) {
- case State::INIT:
- case State::HAS_MINUS:
- switch (c) {
- case '-':
- // Do not allow multiple minus signs
- if (state == State::HAS_MINUS) {
- logger.errorAt(ERR_UNEXPECTED_CHAR, reader);
- return false;
- }
- state = State::HAS_MINUS;
- s = -1;
- break;
- case '0':
- // Remember a leading zero for the detection of "0x"
- state = State::LEADING_ZERO;
- break;
- case '.':
- // Remember a leading point as ".eXXX" is invalid
- state = State::LEADING_POINT;
- break;
- default:
- state = State::INT;
- if (!appendChar(c, 10, Part::A, reader, logger)) {
- return false;
- }
- break;
- }
- break;
- case State::LEADING_ZERO:
- if (c == 'x' || c == 'X') {
- state = State::HEX;
- break;
- }
- // fallthrough
- case State::INT:
- switch (c) {
- case '.':
- state = State::POINT;
- break;
- case 'e':
- case 'E':
- state = State::EXP_INIT;
- break;
- default:
- state = State::INT;
- if (!appendChar(c, 10, Part::A, reader, logger)) {
- return false;
- }
- break;
- }
- break;
- case State::HEX:
- if (!appendChar(c, 16, Part::A, reader, logger)) {
- return false;
- }
- break;
- case State::LEADING_POINT:
- case State::POINT:
- switch (c) {
- case 'e':
- case 'E':
- if (state == State::LEADING_POINT) {
- logger.errorAt(ERR_UNEXPECTED_CHAR, reader);
- return false;
- }
- state = State::EXP_INIT;
- break;
- default:
- state = State::POINT;
- if (!appendChar(c, 10, Part::N, reader, logger)) {
- return false;
- }
- break;
- }
- break;
- case State::EXP_HAS_MINUS:
- case State::EXP_INIT:
- if (c == '-') {
- if (state == State::EXP_HAS_MINUS) {
- logger.errorAt(ERR_UNEXPECTED_CHAR, reader);
- return false;
- }
- state = State::EXP_HAS_MINUS;
- sE = -1;
- } else {
- state = State::EXP;
- if (!appendChar(c, 10, Part::E, reader, logger)) {
- return false;
- }
- }
- break;
- case State::EXP:
- if (!appendChar(c, 10, Part::E, reader, logger)) {
- return false;
- }
- break;
- }
- reader.consumePeek();
- }
-
- // States in which ending is valid. Log an error in other states
- if (state == State::LEADING_ZERO || state == State::HEX ||
- state == State::INT || state == State::POINT ||
- state == State::EXP) {
- return true;
- }
- logger.errorAt(ERR_UNEXPECTED_END, reader);
- return false;
- }
-};
-
-/* Class Reader */
-
-static const int STATE_INIT = 0;
-static const int STATE_IN_STRING = 1;
-static const int STATE_IN_ARRAY = 2;
-static const int STATE_EXPECT_COMMA = 3;
-static const int STATE_ESCAPE = 4;
-static const int STATE_WHITESPACE = 5;
-static const int STATE_RESYNC = 6;
-
-template <class T>
-static std::pair<bool, T> error(CharReader &reader, Logger &logger,
- const char *err, T res)
-{
- logger.errorAt(err, reader);
- return std::make_pair(false, std::move(res));
-}
-
-std::pair<bool, std::string> Reader::parseString(
- CharReader &reader, Logger &logger,
- const std::unordered_set<char> *delims)
-{
- // Initialize the internal state
- int state = STATE_INIT;
- char quote = 0;
- std::stringstream res;
-
- // Consume all whitespace
- reader.consumeWhitespace();
-
- // Statemachine whic iterates over each character in the stream
- // TODO: Combination of peeking and consumePeek is stupid as consumePeek is
- // the default (read and putBack would obviously be better, yet the latter
- // is not trivial to implement in the current CharReader).
- char c;
- while (reader.peek(c)) {
- switch (state) {
- case STATE_INIT:
- if (c == '"' || c == '\'') {
- quote = c;
- state = STATE_IN_STRING;
- break;
- } else if (delims && delims->count(c)) {
- return error(reader, logger, ERR_UNEXPECTED_END, res.str());
- }
- return error(reader, logger, ERR_UNEXPECTED_CHAR, res.str());
- case STATE_IN_STRING:
- if (c == quote) {
- reader.consumePeek();
- return std::make_pair(true, res.str());
- } else if (c == '\\') {
- state = STATE_ESCAPE;
- reader.consumePeek();
- break;
- } else if (c == '\n') {
- return error(reader, logger, ERR_UNTERMINATED, res.str());
- }
- res << c;
- reader.consumePeek();
- break;
- case STATE_ESCAPE:
- // Handle all possible special escape characters
- switch (c) {
- case 'b':
- res << '\b';
- break;
- case 'f':
- res << '\f';
- break;
- case 'n':
- res << '\n';
- break;
- case 'r':
- res << '\r';
- break;
- case 't':
- res << '\t';
- break;
- case 'v':
- res << '\v';
- break;
- case '\'':
- res << '\'';
- break;
- case '"':
- res << '"';
- break;
- case '\\':
- res << '\\';
- break;
- case '\n':
- break;
- case 'x':
- // TODO: Parse Latin-1 sequence hex XX
- break;
- case 'u':
- // TODO: Parse 16-Bit unicode character hex XXXX
- break;
- default:
- if (Utils::isNumeric(c)) {
- // TODO: Parse octal 000 sequence
- } else {
- logger.errorAt(ERR_INVALID_ESCAPE, reader);
- }
- break;
- }
-
- // Switch back to the "normal" state
- state = STATE_IN_STRING;
- reader.consumePeek();
- break;
- }
- }
- return error(reader, logger, ERR_UNEXPECTED_END, res.str());
-}
-
-std::pair<bool, Variant::arrayType> Reader::parseArray(
- CharReader &reader, Logger &logger, char delim)
-{
- Variant::arrayType res;
- bool hadError = false;
- int state = delim ? STATE_IN_ARRAY : STATE_INIT;
- delim = delim ? delim : ']';
- char c;
-
- // Consume all whitespace
- reader.consumeWhitespace();
-
- // Iterate over the characters, use the parseGeneric function to read the
- // pairs
- while (reader.peek(c)) {
- // Generically handle the end of the array
- if (state != STATE_INIT && c == delim) {
- reader.consumePeek();
- return std::make_pair(!hadError, res);
- }
-
- switch (state) {
- case STATE_INIT:
- if (c != '[') {
- return error(reader, logger, ERR_UNEXPECTED_CHAR, res);
- }
- state = STATE_IN_ARRAY;
- reader.consumePeek();
- break;
- case STATE_IN_ARRAY: {
- // Try to read an element using the parseGeneric function
- reader.resetPeek();
- auto elem = parseGeneric(reader, logger, {',', delim});
- res.push_back(elem.second);
-
- // If the reader had no error, expect an comma, otherwise skip
- // to the next comma in the stream
- if (elem.first) {
- state = STATE_EXPECT_COMMA;
- } else {
- state = STATE_RESYNC;
- hadError = true;
- }
- break;
- }
- case STATE_EXPECT_COMMA:
- // Skip whitespace
- if (c == ',') {
- state = STATE_IN_ARRAY;
- } else if (!Utils::isWhitespace(c)) {
- hadError = true;
- state = STATE_RESYNC;
- logger.errorAt(ERR_UNEXPECTED_CHAR, reader);
- }
- reader.consumePeek();
- break;
- case STATE_RESYNC:
- // Just wait for another comma to arrive
- if (c == ',') {
- state = STATE_IN_ARRAY;
- }
- reader.consumePeek();
- break;
- }
- }
- return error(reader, logger, ERR_UNEXPECTED_END, res);
-}
-
-std::pair<bool, std::string> Reader::parseUnescapedString(
- CharReader &reader, Logger &logger,
- const std::unordered_set<char> &delims)
-{
- std::stringstream res;
- std::stringstream buf;
- char c;
-
- // Consume all whitespace
- reader.consumeWhitespace();
-
- // Copy all characters, skip whitespace at the end
- int state = STATE_IN_STRING;
- while (reader.peek(c)) {
- if (delims.count(c)) {
- reader.resetPeek();
- return std::make_pair(true, res.str());
- } else if (Utils::isWhitespace(c)) {
- // Do not add whitespace to the output buffer
- state = STATE_WHITESPACE;
- buf << c;
- } else {
- // If we just hat a sequence of whitespace, append it to the output
- // buffer and continue
- if (state == STATE_WHITESPACE) {
- res << buf.str();
- buf.str(std::string{});
- buf.clear();
- state = STATE_IN_STRING;
- }
- res << c;
- }
- reader.consumePeek();
- }
- return std::make_pair(true, res.str());
-}
-
-std::pair<bool, int64_t> Reader::parseInteger(
- CharReader &reader, Logger &logger,
- const std::unordered_set<char> &delims)
-{
- Number n;
- if (n.parse(reader, logger, delims)) {
- // Only succeed if the parsed number is an integer, otherwise this is an
- // error
- if (n.isInt()) {
- return std::make_pair(true, n.intValue());
- } else {
- return error(reader, logger, ERR_INVALID_INTEGER, n.intValue());
- }
- }
- return std::make_pair(false, n.intValue());
-}
-
-std::pair<bool, double> Reader::parseDouble(
- CharReader &reader, Logger &logger,
- const std::unordered_set<char> &delims)
-{
- Number n;
- bool res = n.parse(reader, logger, delims);
- return std::make_pair(res, n.doubleValue());
-}
-
-std::pair<bool, Variant> Reader::parseGeneric(
- CharReader &reader, Logger &logger,
- const std::unordered_set<char> &delims)
-{
- char c;
-
- // Skip all whitespace characters
- reader.consumeWhitespace();
- while (reader.peek(c)) {
- // Stop if a delimiter is reached
- if (delims.count(c)) {
- return error(reader, logger, ERR_UNEXPECTED_END, nullptr);
- }
-
- // Parse a string if a quote is reached
- if (c == '"' || c == '\'') {
- auto res = parseString(reader, logger);
- return std::make_pair(res.first, res.second.c_str());
- }
-
- if (c == '[') {
- // TODO: Parse struct descriptor
- }
-
- // Try to parse everything that looks like a number as number
- if (Utils::isNumeric(c) || c == '-') {
- Number n;
-
- // Fork the reader
- utils::CharReaderFork fork = reader.fork();
-
- // TODO: Fork logger
-
- // Try to parse the number
- if (n.parse(fork, logger, delims)) {
- // Parsing was successful, advance the reader
- fork.commit();
- if (n.isInt()) {
- return std::make_pair(
- true,
- Variant{static_cast<Variant::intType>(n.intValue())});
- } else {
- return std::make_pair(true, n.doubleValue());
- }
- }
- }
-
- // Parse an unescaped string in any other case
- auto res = parseUnescapedString(reader, logger, delims);
-
- // Handling for special primitive values
- if (res.first) {
- if (res.second == "true") {
- return std::make_pair(true, Variant{true});
- }
- if (res.second == "false") {
- return std::make_pair(true, Variant{false});
- }
- if (res.second == "null") {
- return std::make_pair(true, Variant{nullptr});
- }
- }
- return std::make_pair(res.first, res.second.c_str());
- }
- return error(reader, logger, ERR_UNEXPECTED_END, nullptr);
-}
-}
-}
-
diff --git a/src/core/variant/Reader.hpp b/src/core/variant/Reader.hpp
deleted file mode 100644
index 4114d46..0000000
--- a/src/core/variant/Reader.hpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- 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 Reader.hpp
- *
- * Provides parsers for various micro formats. These formats include integers,
- * doubles, strings, JSON and the Ousía struct notation.
- *
- * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
- */
-
-#ifndef _OUSIA_VARIANT_READER_HPP_
-#define _OUSIA_VARIANT_READER_HPP_
-
-#include <cstdint>
-#include <unordered_set>
-#include <utility>
-
-#include <core/utils/CharReader.hpp>
-#include <core/Logger.hpp>
-
-#include "Variant.hpp"
-
-namespace ousia {
-namespace variant {
-
-class Reader {
-private:
- /**
- * Parses a string which may either be enclosed by " or ', unescapes
- * entities in the string as specified for JavaScript.
- *
- * @param reader is a reference to the CharReader instance which is
- * the source for the character data. The reader will be positioned after
- * the terminating quote character or at the terminating delimiting
- * character.
- * @param logger is the logger instance that should be used to log error
- * messages and warnings.
- * @param delims is an optional set of delimiters after which parsing has to
- * be stopped (the delimiters may occur inside the actual string, but not
- * outside). If nullptr is given, no delimiter is used and a complete string
- * is read.
- */
- static std::pair<bool, std::string> parseString(
- CharReader &reader, Logger &logger,
- const std::unordered_set<char> *delims);
-
-public:
- /**
- * Parses a string which may either be enclosed by " or ', unescapes
- * entities in the string as specified for JavaScript.
- *
- * @param reader is a reference to the CharReader instance which is
- * the source for the character data. The reader will be positioned after
- * the terminating quote character or at the terminating delimiting
- * character.
- * @param logger is the logger instance that should be used to log error
- * messages and warnings.
- * @param delims is a set of delimiters after which parsing has to
- * be stopped (the delimiters may occur inside the actual string, but not
- * outside).
- */
- static std::pair<bool, std::string> parseString(
- CharReader &reader, Logger &logger,
- const std::unordered_set<char> &delims)
- {
- return parseString(reader, logger, &delims);
- }
-
- /**
- * Parses a string which may either be enclosed by " or ', unescapes
- * entities in the string as specified for JavaScript.
- *
- * @param reader is a reference to the CharReader instance which is
- * the source for the character data. The reader will be positioned after
- * the terminating quote character or at the terminating delimiting
- * character.
- * @param logger is the logger instance that should be used to log error
- * messages and warnings.
- */
- static std::pair<bool, std::string> parseString(CharReader &reader,
- Logger &logger)
- {
- return parseString(reader, logger, nullptr);
- }
-
- /**
- * Extracts an unescaped string from the given buffered char reader
- * instance. This function just reads text until one of the given delimiter
- * characters is reached.
- *
- * @param reader is a reference to the CharReader instance which is
- * the source for the character data. The reader will be positioned at the
- * terminating delimiting character.
- * @param delims is a set of characters which will terminate the string.
- * These characters are not included in the result. May not be nullptr.
- */
- static std::pair<bool, std::string> parseUnescapedString(
- CharReader &reader, Logger &logger,
- const std::unordered_set<char> &delims);
-
- /**
- * Parses an integer from the given buffered char reader instance until one
- * of the given delimiter characters is reached.
- *
- * @param reader is a reference to the CharReader instance from
- * which the character data should been reader. The reader will be
- * positioned at the terminating delimiting character or directly after the
- * integer.
- */
- static std::pair<bool, int64_t> parseInteger(
- CharReader &reader, Logger &logger,
- const std::unordered_set<char> &delims);
-
- /**
- * Parses an double from the given buffered char reader instance until one
- * of the given delimiter characters is reached.
- *
- * @param reader is a reference to the CharReader instance from
- * which the character data should been reader. The reader will be
- * positioned at the terminating delimiting character or directly after the
- * integer.
- */
- static std::pair<bool, double> parseDouble(
- CharReader &reader, Logger &logger,
- const std::unordered_set<char> &delims);
-
- /**
- * Parses an array of values.
- */
- static std::pair<bool, Variant::arrayType> parseArray(
- CharReader &reader, Logger &logger, char delim = 0);
-
- /**
- * Tries to parse the most specific item from the given stream until one of
- * the given delimiters is reached or a meaningful literal has been read.
- * The resulting variant represents the value that has been read.
- *
- * @param reader is a reference to the CharReader instance which is
- * the source for the character data. The reader will be positioned at the
- * terminating delimiting character.
- * @param delims is a set of characters which will terminate the string.
- * These characters are not included in the result. May not be nullptr.
- */
- static std::pair<bool, Variant> parseGeneric(
- CharReader &reader, Logger &logger,
- const std::unordered_set<char> &delims);
-};
-}
-}
-
-#endif /* _OUSIA_VARIANT_READER_HPP_ */
-
diff --git a/src/core/variant/Variant.cpp b/src/core/variant/Variant.cpp
deleted file mode 100644
index d33cd4f..0000000
--- a/src/core/variant/Variant.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- 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 <sstream>
-
-#include <core/Utils.hpp>
-
-#include "Variant.hpp"
-
-namespace ousia {
-
-/* Class Variant::TypeException */
-
-Variant::TypeException::TypeException(Type actualType, Type requestedType)
- : OusiaException(std::string("Variant: Requested \"") +
- Variant::getTypeName(requestedType) +
- std::string("\" but is \"") +
- Variant::getTypeName(actualType) + std::string("\"")),
- actualType(actualType),
- requestedType(requestedType)
-{
-}
-
-/* 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 "double";
- case Type::STRING:
- return "string";
- case Type::ARRAY:
- return "array";
- case Type::MAP:
- return "map";
- }
- return "unknown";
-}
-
-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;
- case Type::STRING:
- return true;
- case Type::ARRAY:
- return true;
- case Type::MAP:
- return true;
- }
- return false;
-}
-
-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:
- return 0; // TODO: Parse string as int
- case Type::ARRAY: {
- const arrayType &a = asArray();
- return (a.size() == 1) ? a[0].toInt() : 0;
- }
- case Type::MAP:
- return 0;
- }
- return false;
-}
-
-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:
- return 0.0; // TODO: Parse string as double
- case Type::ARRAY: {
- const arrayType &a = asArray();
- return (a.size() == 1) ? a[0].toDouble() : 0;
- }
- case Type::MAP:
- return 0;
- }
- return false;
-}
-
-Variant::stringType Variant::toString(bool escape) const
-{
- switch (getType()) {
- case Type::NULLPTR:
- return "null";
- case Type::BOOL:
- return asBool() ? "true" : "false";
- case Type::INT:
- return std::to_string(asInt());
- case Type::DOUBLE:
- return std::to_string(asDouble());
- case Type::STRING: {
- // TODO: Use proper serialization function
- std::stringstream ss;
- ss << "\"" << asString() << "\"";
- return ss.str();
- }
- case Type::ARRAY:
- return Utils::join(asArray(), ", ", "[", "]");
- case Type::MAP:
- return Utils::join(asMap(), ", ", "{", "}");
- }
- return "";
-}
-
-}
-
diff --git a/src/core/variant/Variant.hpp b/src/core/variant/Variant.hpp
deleted file mode 100644
index 1e62644..0000000
--- a/src/core/variant/Variant.hpp
+++ /dev/null
@@ -1,766 +0,0 @@
-/*
- 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 data given by the end user 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>
-#include <ostream>
-
-// 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 {
-namespace variant {
-
-/**
- * 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;
- };
-
- /**
- * 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)
- {
- destroy();
- 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)
- {
- destroy();
- 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) : ptrVal(nullptr) { 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) : ptrVal(nullptr) { move(std::move(v)); }
-
- /**
- * Default constructor. Type is set to Type:null.
- */
- Variant() : ptrVal(nullptr) { setNull(); }
-
- /**
- * Default destructor, frees any memory that was allocated on the heap.
- */
- ~Variant() { destroy(); }
-
- /**
- * Constructor for null values. Initializes the variant as null value.
- */
- Variant(std::nullptr_t) : ptrVal(nullptr) { setNull(); }
-
- /**
- * Constructor for boolean values.
- *
- * @param b boolean value.
- */
- Variant(boolType b) : ptrVal(nullptr) { setBool(b); }
-
- /**
- * Constructor for integer values.
- *
- * @param i integer value.
- */
- Variant(intType i) : ptrVal(nullptr) { setInt(i); }
-
- /**
- * Constructor for double values.
- *
- * @param d double value.
- */
- Variant(doubleType d) : ptrVal(nullptr) { 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) : ptrVal(nullptr) { 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(arrayType a) : ptrVal(nullptr) { 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(mapType m) : ptrVal(nullptr) { 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 d is the double value to which the variant should be set.
- */
- Variant &operator=(doubleType d)
- {
- setDouble(d);
- return *this;
- }
-
- /**
- * Assign a zero terminated const char array.
- *
- * @param s is the zero terminated const char array to which the variant
- * should be set.
- */
- Variant &operator=(const char *s)
- {
- setString(s);
- 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); }
-
- /**
- * Returns the value of the Variant as boolean, performs type conversion.
- *
- * @return the Variant value converted to a boolean value.
- */
- boolType toBool() const;
-
- /**
- * Returns the value of the Variant as integer, performs type conversion.
- *
- * @return the Variant value converted to an integer value.
- */
- intType toInt() const;
-
- /**
- * Returns the value of the Variant as double, performs type conversion.
- *
- * @return the Variant value converted to a double value.
- */
- doubleType toDouble() const;
-
- /**
- * Returns the value of the Variant as string, performs type conversion.
- *
- * @return the value of the variant as string.
- * @param escape if set to true, adds double quotes to strings and escapes
- * them properly (resulting in a more or less JSONesque output).
- */
- stringType toString(bool escape = false) const;
-
- /**
- * 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()); }
-
- /**
- * Prints the Variant to the output stream.
- */
- friend std::ostream &operator<<(std::ostream &os, const Variant &v)
- {
- return os << v.toString(true);
- }
-
- /**
- * Prints a key value pair 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);
- }
-
- /*
- * Comprison operators.
- */
-
- 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::STRING:
- return lhs.asString() < rhs.asString();
- case Type::ARRAY:
- return lhs.asArray() < rhs.asArray();
- case Type::MAP:
- return lhs.asMap() < rhs.asMap();
- }
- throw OusiaException("Internal Error! Unknown type!");
- }
- friend bool operator>(const Variant &lhs, const Variant &rhs)
- {
- return rhs < lhs;
- }
- friend bool operator<=(const Variant &lhs, const Variant &rhs)
- {
- return !(lhs > rhs);
- }
- friend bool operator>=(const Variant &lhs, const Variant &rhs)
- {
- return !(lhs < 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:
- return lhs.asString() == rhs.asString();
- case Type::ARRAY:
- return lhs.asArray() == rhs.asArray();
- case Type::MAP:
- return lhs.asMap() == rhs.asMap();
- }
- throw OusiaException("Internal Error! Unknown type!");
- }
-
- friend bool operator!=(const Variant &lhs, const Variant &rhs)
- {
- return !(lhs == rhs);
- }
-};
-}
-
-// Alias for the (very often used and unambigous) variant class
-using Variant = variant::Variant;
-}
-
-#endif /* _OUSIA_VARIANT_HPP_ */
-