summaryrefslogtreecommitdiff
path: root/src/core/common/Argument.cpp
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-12 00:00:07 +0100
committerAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-12 00:00:07 +0100
commit874a2a6c9a1f5196c65850cd67cfd6992ff0c95e (patch)
tree593c3f56866a60cd92d0a79a06bbcfce292f1d40 /src/core/common/Argument.cpp
parent57346af125d4274187bf4af424d13fde072155de (diff)
Added Argument and Arguments class
Diffstat (limited to 'src/core/common/Argument.cpp')
-rw-r--r--src/core/common/Argument.cpp282
1 files changed, 282 insertions, 0 deletions
diff --git a/src/core/common/Argument.cpp b/src/core/common/Argument.cpp
new file mode 100644
index 0000000..78dd4b4
--- /dev/null
+++ b/src/core/common/Argument.cpp
@@ -0,0 +1,282 @@
+/*
+ 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 "Argument.hpp"
+#include "Exceptions.hpp"
+#include "Logger.hpp"
+#include "Rtti.hpp"
+#include "Utils.hpp"
+#include "VariantConverter.hpp"
+
+namespace ousia {
+
+/* Class Argument */
+
+Argument::Argument(std::string name, const RttiType &type,
+ const RttiType &innerType, Variant defaultValue,
+ bool hasDefault)
+ : type(type),
+ innerType(innerType),
+ name(std::move(name)),
+ defaultValue(std::move(defaultValue)),
+ hasDefault(hasDefault)
+{
+}
+
+Argument::Argument(std::string name, const RttiType &type, Variant defaultValue)
+ : Argument(std::move(name), type, RttiTypes::None, defaultValue, true)
+{
+}
+
+Argument::Argument(std::string name, const RttiType &type)
+ : Argument(std::move(name), type, RttiTypes::None, nullptr, false)
+{
+}
+
+Argument Argument::Bool(std::string name)
+{
+ return Argument{name, RttiTypes::Bool};
+}
+
+Argument Argument::Bool(std::string name, Variant::boolType defaultValue)
+{
+ return Argument{name, RttiTypes::Bool, defaultValue};
+}
+
+Argument Argument::Int(std::string name)
+{
+ return Argument{name, RttiTypes::Int};
+}
+
+Argument Argument::Int(std::string name, Variant::intType defaultValue)
+{
+ return Argument{name, RttiTypes::Int, defaultValue};
+}
+
+Argument Argument::Double(std::string name)
+{
+ return Argument{name, RttiTypes::Double};
+}
+
+Argument Argument::Double(std::string name, Variant::doubleType defaultValue)
+{
+ return Argument{name, RttiTypes::Double, defaultValue};
+}
+
+Argument Argument::String(std::string name)
+{
+ return Argument{name, RttiTypes::String};
+}
+
+Argument Argument::String(std::string name,
+ const Variant::stringType &defaultValue)
+{
+ return Argument{name, RttiTypes::String, Variant::fromString(defaultValue)};
+}
+
+Argument Argument::Object(std::string name, const RttiType &type)
+{
+ return Argument(std::move(name), type, RttiTypes::None, nullptr, false);
+}
+
+Argument Argument::Object(std::string name, const RttiType &type,
+ std::nullptr_t)
+{
+ return Argument(std::move(name), type, RttiTypes::None, nullptr, true);
+}
+
+Argument Argument::Function(std::string name)
+{
+ return Argument(std::move(name), RttiTypes::Function);
+}
+
+Argument Argument::Function(std::string name,
+ Variant::functionType defaultValue)
+{
+ return Argument(std::move(name), RttiTypes::Function,
+ Variant::fromFunction(defaultValue));
+}
+
+Argument Argument::Array(std::string name)
+{
+ return Argument(std::move(name), RttiTypes::Array);
+}
+
+Argument Argument::Array(std::string name,
+ const Variant::arrayType &defaultValue)
+{
+ return Argument(std::move(name), RttiTypes::Array, defaultValue);
+}
+
+Argument Argument::Array(std::string name, const RttiType &innerType)
+{
+ return Argument(std::move(name), RttiTypes::Array, innerType, nullptr,
+ false);
+}
+
+Argument Argument::Array(std::string name, const RttiType &innerType,
+ const Variant::arrayType &defaultValue)
+{
+ return Argument(std::move(name), RttiTypes::Array, innerType, defaultValue,
+ true);
+}
+
+Argument Argument::Map(std::string name)
+{
+ return Argument(std::move(name), RttiTypes::Map);
+}
+
+Argument Argument::Map(std::string name, const Variant::mapType &defaultValue)
+{
+ return Argument(std::move(name), RttiTypes::Map, defaultValue);
+}
+
+Argument Argument::Map(std::string name, const RttiType &innerType)
+{
+ return Argument(std::move(name), RttiTypes::Map, innerType, nullptr, false);
+}
+
+Argument Argument::Map(std::string name, const RttiType &innerType,
+ const Variant::mapType &defaultValue)
+{
+ return Argument(std::move(name), RttiTypes::Map, innerType, defaultValue,
+ true);
+}
+
+bool Argument::validate(Variant &var, Logger &logger)
+{
+ if (!VariantConverter::convert(var, type, innerType, logger,
+ VariantConverter::Mode::SAFE)) {
+ if (hasDefault) {
+ var = defaultValue;
+ }
+ return false;
+ }
+ return true;
+}
+
+/* Class Arguments */
+
+static std::unordered_map<std::string, size_t> buildArgumentNames(
+ std::initializer_list<Argument> arguments)
+{
+ // Make sure the name is unique
+ std::unordered_map<std::string, size_t> res;
+ size_t i = 0;
+ for (const Argument &arg : arguments) {
+ if (!Utils::isIdentifier(arg.name)) {
+ throw OusiaException{std::string("Argument name ") + arg.name +
+ std::string(" is not a valid identifier!")};
+ }
+ if (!res.emplace(arg.name, i++).second) {
+ throw OusiaException{
+ std::string("Argument names must be unique (") + arg.name +
+ std::string(")!")};
+ }
+ }
+ return res;
+}
+
+Arguments::Arguments(std::initializer_list<Argument> arguments)
+ : arguments(arguments), names(buildArgumentNames(arguments))
+{
+}
+
+bool Arguments::validateArray(Variant::arrayType &arr, Logger &logger)
+{
+ // Fetch the number of arguments N and the initial array size n
+ const size_t n = arr.size();
+ const size_t N = arguments.size();
+ bool ok = true;
+
+ // Make sure the argument list is not too long
+ if (n > N) {
+ ok = false;
+ logger.error(std::string("Too many arguments: expected ") +
+ std::to_string(N) + std::string(" arguments, but got ") +
+ std::to_string(n));
+ }
+
+ // Resize the array to the total number of elements
+ arr.resize(N);
+
+ // Make sure the given attributes have to correct type, insert default
+ // values
+ for (size_t a = 0; a < N; a++) {
+ if (a < n) {
+ ok = ok && arguments[a].validate(arr[a], logger);
+ } else {
+ if (arguments[a].hasDefault) {
+ arr[a] = arguments[a].defaultValue;
+ } else {
+ logger.error(std::string("Missing argument ") +
+ std::to_string(a + 1) + std::string("(") +
+ arguments[a].name + std::string(")!"));
+ ok = false;
+ }
+ }
+ }
+
+ return ok;
+}
+
+bool Arguments::validateMap(Variant::mapType &map, Logger &logger,
+ bool ignoreUnknown)
+{
+ // Fetch the number of arguments N
+ const size_t N = arguments.size();
+ std::vector<bool> set(N);
+ bool ok = true;
+
+ // Iterate over the map entries and search for the corresponding argument
+ for (auto &e : map) {
+ // Check whether an argument with the name of the current entry exists
+ auto it = names.find(e.first);
+ if (it != names.end()) {
+ // Fetch the corresponding index in the "arguments" array
+ size_t idx = it->second;
+ set[idx] = arguments[idx].validate(e.second, logger);
+ ok = ok && set[idx];
+ } else {
+ if (ignoreUnknown) {
+ logger.note(std::string("Ignoring argument ") + e.first);
+ } else {
+ logger.error(std::string("Unknown argument ") + e.first +
+ std::string("!"));
+ ok = false;
+ }
+ }
+ }
+
+ // Insert all unset arguments
+ for (size_t a = 0; a < N; a++) {
+ if (!set[a]) {
+ if (arguments[a].hasDefault) {
+ map[arguments[a].name] = arguments[a].defaultValue;
+ } else {
+ logger.error(std::string("Missing argument ") +
+ arguments[a].name);
+ ok = false;
+ }
+ }
+ }
+
+ return ok;
+}
+}
+