diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/model/RangeSet.hpp | 326 | ||||
| -rw-r--r-- | src/core/script/Variant.cpp | 80 | ||||
| -rw-r--r-- | src/core/script/Variant.hpp | 274 | 
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_ */ +  | 
