summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/model/RangeSet.hpp326
-rw-r--r--src/core/script/Variant.cpp80
-rw-r--r--src/core/script/Variant.hpp274
3 files changed, 680 insertions, 0 deletions
diff --git a/src/core/model/RangeSet.hpp b/src/core/model/RangeSet.hpp
new file mode 100644
index 0000000..ef86363
--- /dev/null
+++ b/src/core/model/RangeSet.hpp
@@ -0,0 +1,326 @@
+/*
+ Ousía
+ Copyright (C) 2014 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_MODEL_RANGE_SET_HPP_
+#define _OUSIA_MODEL_RANGE_SET_HPP_
+
+#include <limits>
+#include <set>
+
+namespace ousia {
+namespace model {
+/**
+ * The Range structure represents an interval of numerical values of type T.
+ */
+template <typename T>
+struct Range {
+ /**
+ * Start is the start value of the range.
+ */
+ T start;
+
+ /**
+ * End is the end value of the range (inclusively).
+ */
+ T end;
+
+ /**
+ * Default constructor of the range class. The range is initialized as
+ * invalid, with start being set to the maximum possible value of the
+ * numerical type T, and end being set to the minimum possible value.
+ */
+ Range() :
+ start(std::numeric_limits<T>::max()),
+ end(std::numeric_limits<T>::min())
+ {
+ // Do nothing here
+ }
+
+ /**
+ * Copies the given start and end value. The given values are not checked
+ * for validity. Use the "isValid"
+ *
+ * @param start is the minimum value the range still covers.
+ * @param end is the maximum value the range still covers.
+ */
+ Range(const T &start, const T &end) :
+ start(start), end(end)
+ {
+ // Do nothing here
+ }
+
+ /**
+ * Creates a range that covers exactly one element, namely the value given
+ * as parameter n.
+ */
+ Range(const T &n) :
+ start(n), end(n)
+ {
+ // Do nothing here
+ }
+
+ /**
+ * Returns true if this range is valid, e.g. its start value is smaller or
+ * equal to its end value.
+ *
+ * @return true if start is smaller or equal to end, false otherwise.
+ */
+ bool isValid() const
+ {
+ return start <= end;
+ }
+
+ /**
+ * Checks whether the given value lies inside the range.
+ *
+ * @param v is the value that is being checked.
+ * @return true if the value lies within the range, false otherwise.
+ */
+ bool inRange(T v) const
+ {
+ return (v >= start) && (v <= end);
+ }
+
+ /**
+ * Checks whether the given range overlapps with another range. Not that
+ * this check is only meaningful if both ranges are valid.
+ *
+ * @param r is the range that should be checked for overlapping with this
+ * range.
+ */
+ bool overlapps(const Range<T> &r) const
+ {
+ return (((r.start >= start) || (r.end >= start))
+ && ((r.start <= end) || (r.end <= end)));
+ }
+
+ /**
+ * Returns true if the two given ranges are neighbours (their limits only
+ * differ in the smallest representable difference between them).
+ */
+ bool neighbours(const Range<T> &r) const
+ {
+ constexpr T eps = std::numeric_limits<T>::is_integer
+ ? 1 : std::numeric_limits<T>::epsilon();
+ return ((r.start > end) && ((r.start - eps) <= end))
+ || ((r.end < start) && ((r.end + eps) >= start));
+ }
+
+ /**
+ * Checks whether the given range completely covers this range.
+ */
+ bool coveredBy(const Range<T> &r) const
+ {
+ return (r.start <= start) && (r.end >= end);
+ }
+
+ /**
+ * Checks whether this range completely covers the given range.
+ */
+ bool covers(const Range<T> &r) const
+ {
+ return r.coveredBy(*this);
+ }
+
+ /**
+ * Calculates the union of the two ranges -- not that this operation is only
+ * valid if the ranges overlapp. Use the RangeSet class if you cannot
+ * guarantee that.
+ */
+ Range<T> merge(const Range<T> &r) const
+ {
+ return Range(std::min(start, r.start), std::max(end, r.end));
+ }
+
+ /**
+ * Returns a range that represents the spans the complete set defined by the
+ * given type T.
+ */
+ static Range<T> typeRange()
+ {
+ return Range(std::numeric_limits<T>::min(),
+ std::numeric_limits<T>::max());
+ }
+
+ /**
+ * Returns a range that represents the spans the complete set defined by the
+ * given type T up to a given value.
+ *
+ * @param till is the value up to which the range should be defined (till is
+ * included in the set).
+ */
+ static Range<T> typeRangeUntil(const T &till)
+ {
+ return Range(std::numeric_limits<T>::min(), till);
+ }
+
+ /**
+ * Returns a range that represents the spans the complete set defined by the
+ * given type T up to a given value.
+ *
+ * @param from is the value from which the range should be defined (from is
+ * included in the set).
+ */
+ static Range<T> typeRangeFrom(const T &from)
+ {
+ return Range(from, std::numeric_limits<T>::max());
+ }
+};
+
+/**
+ * RangeComp is a comperator used to order to sort the ranges within the
+ * ranges list. Sorts by the start element.
+ */
+template<typename T>
+struct RangeComp {
+ bool operator() (const Range<T>& lhs, const Range<T>& rhs) const
+ {
+ return lhs.start < rhs.start;
+ }
+};
+
+/**
+ * RangeSet represents a set of ranges of the given numerical type and is thus
+ * capable of representing any possible subset of the given numerical type T.
+ */
+template<typename T>
+class RangeSet {
+
+protected:
+ /**
+ * Set of ranges used internally.
+ */
+ std::set<Range<T>, RangeComp<T>> ranges;
+
+ /**
+ * Returns an iterator to the first element in the ranges list that overlapps
+ * with the given range.
+ *
+ * @param r is the range for which the first overlapping element should be
+ * found.
+ * @return an iterator pointing to the first overlapping element or to the
+ * end of the list if no such element was found.
+ */
+ typename std::set<Range<T>, RangeComp<T>>::iterator firstOverlapping(
+ const Range<T> &r, const bool allowNeighbours)
+ {
+ // Find the element with the next larger start value compared to the
+ // start value given in r.
+ auto it = ranges.upper_bound(r);
+
+ // Go back one element
+ if (it != ranges.begin()) {
+ it--;
+ }
+
+ // Iterate until an overlapping element is found
+ while (!(it->overlapps(r) || (allowNeighbours && it->neighbours(r)))
+ && (it != ranges.end())) {
+ it++;
+ }
+ return it;
+ }
+
+public:
+ /**
+ * Calculates the union of this range set and the given range.
+ *
+ * @param range is the range that should be merged into this range set.
+ */
+ void merge(Range<T> r)
+ {
+ // Calculate a new range that covers both the new range and all old
+ // ranges in the set -- delete all old elements on the way
+ auto it = firstOverlapping(r, true);
+ while ((it->overlapps(r) || it->neighbours(r)) && it != ranges.end()) {
+ r = r.merge(*it);
+ it = ranges.erase(it);
+ }
+
+ // Insert the new range
+ ranges.insert(r);
+ }
+
+ /**
+ * Calculates the union of this range set and the given range set.
+ *
+ * @param ranges is another range set for which the union with this set
+ * should be calculated.
+ */
+ void merge(const RangeSet<T> &s)
+ {
+ for (Range<T> &r : s.ranges) {
+ merge(r);
+ }
+ }
+
+ /**
+ * Checks whether this range set S contains the given range R:
+ * S u R = R
+ * (The intersection between R and S equals the given range)
+ *
+ * @param r is the range for which the containment should be checked.
+ * @return true if the above condition is met, false otherwise.
+ */
+ bool contains(const Range<T> &r)
+ {
+ auto it = firstOverlapping(r, false);
+ if (it != ranges.end()) {
+ return (*it).covers(r);
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether this range set S1 contains the given range set S2:
+ *
+ * @param s is the range for which the containment should be checked.
+ * @return true if the above condition is met, false otherwise.
+ */
+ bool contains(const RangeSet<T> &s)
+ {
+ bool res = true;
+ for (Range<T> &r : s.ranges) {
+ res = res && contains(r);
+ }
+ return res;
+ }
+
+ /**
+ * Empties the set.
+ */
+ void clear()
+ {
+ ranges.clear();
+ }
+
+ /**
+ * Returns the current list of ranges as a const reference.
+ */
+ const std::set<Range<T>, RangeComp<T>>& getRanges()
+ {
+ return this->ranges;
+ }
+
+};
+
+}
+}
+
+#endif /* _OUSIA_MODEL_RANGE_SET_HPP_ */
+
diff --git a/src/core/script/Variant.cpp b/src/core/script/Variant.cpp
new file mode 100644
index 0000000..623b396
--- /dev/null
+++ b/src/core/script/Variant.cpp
@@ -0,0 +1,80 @@
+/*
+ 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 {
+namespace script {
+
+std::ostream& operator<< (std::ostream& os, const Variant &v)
+{
+ switch (v.type) {
+ case VariantType::none:
+ os << "null";
+ break;
+ case VariantType::integer:
+ os << v.integerValue;
+ break;
+ case VariantType::number:
+ os << v.numberValue;
+ break;
+ case VariantType::string:
+ os << "\"" << v.stringValue << "\"";
+ break;
+ case VariantType::array: {
+ bool first = true;
+ os << "[";
+ for (auto &v2 : v.arrayValue) {
+ if (!first) {
+ os << ", ";
+ }
+ os << v2;
+ first = false;
+ }
+ os << "]";
+ break;
+ }
+ case VariantType::map: {
+ bool first = true;
+ os << "{";
+ for (auto &v2 : v.mapValue) {
+ if (!first) {
+ os << ", ";
+ }
+ os << "\"" << v2.first << "\": " << v2.second;
+ first = false;
+ }
+ os << "}";
+ break;
+ }
+ case VariantType::function:
+ os << "<Function>";
+ break;
+ case VariantType::object:
+ os << "<Object>";
+ break;
+ case VariantType::buffer:
+ os << "<Buffer>";
+ break;
+ }
+ return os;
+}
+
+}
+}
+
diff --git a/src/core/script/Variant.hpp b/src/core/script/Variant.hpp
new file mode 100644
index 0000000..208bfa5
--- /dev/null
+++ b/src/core/script/Variant.hpp
@@ -0,0 +1,274 @@
+/*
+ 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_HPP_
+#define _OUSIA_VARIANT_HPP_
+
+#include <cstdint>
+#include <ostream>
+#include <string>
+#include <vector>
+#include <map>
+
+namespace ousia {
+namespace script {
+
+/**
+ * Enum containing the possible types a variant may have.
+ */
+enum class VariantType {
+ none, integer, number, string, array, map, function, object, buffer
+};
+
+/**
+ * Instances of the Variant class represent any kind of data that is exchanged
+ * between the host application and the script engine.
+ */
+class Variant {
+
+private:
+ VariantType type;
+
+ union {
+ int64_t integerValue;
+ double numberValue;
+ std::string stringValue;
+ std::vector<Variant> arrayValue;
+ std::map<std::string, Variant> mapValue;
+ };
+
+ /**
+ * Private function calling the destructor of the currently used union
+ * member.
+ */
+ void free() {
+ // Explicitly call the destructor
+ switch (type) {
+ case VariantType::string:
+ stringValue.std::string::~string();
+ break;
+ case VariantType::array:
+ arrayValue.std::vector<Variant>::~vector();
+ break;
+ case VariantType::map:
+ mapValue.std::map<std::string, Variant>::~map();
+ break;
+ default:
+ break;
+ }
+
+ // Reset the type
+ type = VariantType::none;
+ }
+
+ /**
+ * Function for copying the content of the given instance v to this
+ * instance. Callers must make sure the storage space has been freed
+ * beforehand.
+ */
+ void copy(const Variant &v)
+ {
+ type = v.type;
+ switch (type) {
+ case VariantType::integer:
+ integerValue = v.integerValue;
+ break;
+ case VariantType::number:
+ numberValue = v.numberValue;
+ break;
+ case VariantType::string:
+ new (&stringValue) std::string(v.stringValue);
+ break;
+ case VariantType::array:
+ new (&arrayValue) std::vector<Variant>(v.arrayValue);
+ break;
+ case VariantType::map:
+ new (&mapValue) std::map<std::string, Variant>(v.mapValue);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Function for moving the content of the given instance v to this instance.
+ * No copy operation is used. Callers must make sure the storage space has
+ * been freed beforehand.
+ */
+ void move(Variant &v)
+ {
+ type = v.type;
+ switch (type) {
+ case VariantType::integer:
+ integerValue = v.integerValue;
+ break;
+ case VariantType::number:
+ numberValue = v.numberValue;
+ break;
+ case VariantType::string:
+ new (&stringValue) std::string(std::move(v.stringValue));
+ break;
+ case VariantType::array:
+ new (&arrayValue) std::vector<Variant>(std::move(v.arrayValue));
+ break;
+ case VariantType::map:
+ new (&mapValue) std::map<std::string, Variant>(std::move(v.mapValue));
+ break;
+ default:
+ break;
+ }
+
+ // Reset the type of v to "none"
+ v.type = VariantType::none;
+ }
+
+public:
+
+ class EBadEntry {};
+
+ Variant(const Variant &v)
+ {
+ copy(v);
+ }
+
+ Variant(Variant &&v)
+ {
+ move(v);
+ }
+
+ Variant& operator=(const Variant &v)
+ {
+ free();
+ copy(v);
+ return *this;
+ }
+
+ Variant& operator=(Variant &&v)
+ {
+ free();
+ move(v);
+ return *this;
+ }
+
+
+ Variant(int64_t i) :
+ type(VariantType::integer),
+ integerValue(i)
+ {
+ // Do nothing here
+ }
+
+ Variant(double d) :
+ type(VariantType::number),
+ numberValue(d)
+ {
+ // Do nothing here
+ }
+
+ Variant(const char *s) :
+ type(VariantType::string)
+ {
+ new (&stringValue) std::string(s);
+ }
+
+ Variant(const std::vector<Variant> &a) :
+ type(VariantType::array)
+ {
+ new (&arrayValue) std::vector<Variant>(a);
+ }
+
+
+ Variant(const std::map<std::string, Variant> &m) :
+ type(VariantType::map)
+ {
+ new (&mapValue) std::map<std::string, Variant>(m);
+ }
+
+ ~Variant()
+ {
+ free();
+ }
+
+ VariantType getType() const
+ {
+ return type;
+ }
+
+ int64_t getIntegerValue() const
+ {
+ switch (type) {
+ case VariantType::integer:
+ return integerValue;
+ case VariantType::number:
+ return static_cast<int64_t>(numberValue);
+ default:
+ throw EBadEntry{};
+ }
+ }
+
+ double getNumberValue() const
+ {
+ switch (type) {
+ case VariantType::integer:
+ return static_cast<double>(integerValue);
+ case VariantType::number:
+ return numberValue;
+ default:
+ throw EBadEntry{};
+ }
+ }
+
+ std::string getStringValue() const
+ {
+ switch (type) {
+ case VariantType::string:
+ return stringValue;
+ default:
+ throw EBadEntry {};
+ }
+ }
+
+ const std::vector<Variant>& getArrayValue() const
+ {
+ switch (type) {
+ case VariantType::array:
+ return arrayValue;
+ default:
+ throw EBadEntry {};
+ }
+ }
+
+ const std::map<std::string, Variant>& getMapValue() const
+ {
+ switch (type) {
+ case VariantType::map:
+ return mapValue;
+ default:
+ throw EBadEntry {};
+ }
+ }
+
+ friend std::ostream& operator<< (std::ostream& os, const Variant &v);
+
+};
+
+}
+}
+
+#endif /* _OUSIA_VARIANT_HPP_ */
+