//////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// /// Copyright 2016 ArangoDB GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is ArangoDB GmbH, Cologne, Germany /// /// @author Jan Steemann //////////////////////////////////////////////////////////////////////////////// #ifndef ARANGODB_PROGRAM_OPTIONS_PARAMETERS_H #define ARANGODB_PROGRAM_OPTIONS_PARAMETERS_H 1 #include "Basics/Common.h" #include #include #include #include #include namespace arangodb { namespace options { // convert a string into a number, base version for signed integer types template inline typename std::enable_if::value, T>::type toNumber( std::string const& value) { auto v = static_cast(std::stoll(value)); if (v < (std::numeric_limits::min)() || v > (std::numeric_limits::max)()) { throw std::out_of_range(value); } return static_cast(v); } // convert a string into a number, base version for unsigned integer types template inline typename std::enable_if::value, T>::type toNumber( std::string const& value) { auto v = static_cast(std::stoull(value)); if (v < (std::numeric_limits::min)() || v > (std::numeric_limits::max)()) { throw std::out_of_range(value); } return static_cast(v); } // convert a string into a number, version for double values template <> inline double toNumber(std::string const& value) { return std::stod(value); } // convert a string into another type, specialized version for numbers template typename std::enable_if::value, T>::type fromString( std::string const& value) { return toNumber(value); } // convert a string into another type, specialized version for string -> string template typename std::enable_if::value, T>::type fromString( std::string const& value) { return value; } // stringify a value, base version for any type template inline std::string stringifyValue(T const& value) { return std::to_string(value); } // stringify a boolean value, specialized version template <> inline std::string stringifyValue(bool const& value) { return value ? "true" : "false"; } // stringify a string value, specialized version template <> inline std::string stringifyValue(std::string const& value) { return "\"" + value + "\""; } // abstract base parameter type struct struct Parameter { Parameter() = default; virtual ~Parameter() {} virtual bool requiresValue() const { return true; } virtual std::string name() const = 0; virtual std::string valueString() const = 0; virtual std::string set(std::string const&) = 0; virtual std::string typeDescription() const { if (requiresValue()) { return std::string("<") + name() + std::string(">"); } return ""; } virtual void toVPack(VPackBuilder&) const = 0; }; // specialized type for boolean values struct BooleanParameter : public Parameter { typedef bool ValueType; explicit BooleanParameter(ValueType* ptr, bool requiresValue = true) : ptr(ptr), required(requiresValue) {} bool requiresValue() const override { return required; } std::string name() const override { return "boolean"; } std::string valueString() const override { return stringifyValue(*ptr); } std::string set(std::string const& value) override { if (!required || value == "true" || value == "false" || value == "on" || value == "off" || value == "1" || value == "0") { *ptr = (!required || value == "true" || value == "on" || value == "1"); return ""; } return "invalid value. expecting 'true' or 'false'"; } std::string typeDescription() const override { if (required) { return Parameter::typeDescription(); } return ""; } void toVPack(VPackBuilder& builder) const override { builder.add(VPackValue(*ptr)); } ValueType* ptr; bool required; }; // specialized type for numeric values // this templated type needs a concrete number type template struct NumericParameter : public Parameter { typedef T ValueType; explicit NumericParameter(ValueType* ptr) : ptr(ptr) {} std::string valueString() const override { return stringifyValue(*ptr); } std::string set(std::string const& value) override { try { ValueType v = toNumber(value); if (v >= (std::numeric_limits::min)() && v <= (std::numeric_limits::max)()) { *ptr = v; return ""; } } catch (...) { return "invalid numeric value"; } return "number out of range"; } void toVPack(VPackBuilder& builder) const override { builder.add(VPackValue(*ptr)); } ValueType* ptr; }; // concrete int16 number value type struct Int16Parameter : public NumericParameter { typedef int16_t ValueType; explicit Int16Parameter(int16_t* ptr) : NumericParameter(ptr) {} std::string name() const override { return "int16"; } }; // concrete uint16 number value type struct UInt16Parameter : public NumericParameter { typedef uint16_t ValueType; explicit UInt16Parameter(ValueType* ptr) : NumericParameter(ptr) {} std::string name() const override { return "uint16"; } }; // concrete int32 number value type struct Int32Parameter : public NumericParameter { typedef int32_t ValueType; explicit Int32Parameter(ValueType* ptr) : NumericParameter(ptr) {} std::string name() const override { return "int32"; } }; // concrete uint32 number value type struct UInt32Parameter : public NumericParameter { typedef uint32_t ValueType; explicit UInt32Parameter(ValueType* ptr) : NumericParameter(ptr) {} std::string name() const override { return "uint32"; } }; // concrete int64 number value type struct Int64Parameter : public NumericParameter { typedef int64_t ValueType; explicit Int64Parameter(ValueType* ptr) : NumericParameter(ptr) {} std::string name() const override { return "int64"; } }; // concrete uint64 number value type struct UInt64Parameter : public NumericParameter { typedef uint64_t ValueType; explicit UInt64Parameter(ValueType* ptr) : NumericParameter(ptr) {} std::string name() const override { return "uint64"; } }; template struct BoundedParameter : public T { BoundedParameter(typename T::ValueType* ptr, typename T::ValueType minValue, typename T::ValueType maxValue) : T(ptr), minValue(minValue), maxValue(maxValue) {} std::string set(std::string const& value) override { try { typename T::ValueType v = toNumber(value); if (v >= (std::numeric_limits::min)() && v <= (std::numeric_limits::max)() && v >= minValue && v <= maxValue) { *this->ptr = v; return ""; } } catch (...) { return "invalid numeric value"; } return "number out of allowed range (" + std::to_string(minValue) + " - " + std::to_string(maxValue) + ")"; } typename T::ValueType minValue; typename T::ValueType maxValue; }; // concrete double number value type struct DoubleParameter : public NumericParameter { typedef double ValueType; explicit DoubleParameter(ValueType* ptr) : NumericParameter(ptr) {} std::string name() const override { return "double"; } }; // string value type struct StringParameter : public Parameter { typedef std::string ValueType; explicit StringParameter(ValueType* ptr) : ptr(ptr) {} std::string name() const override { return "string"; } std::string valueString() const override { return stringifyValue(*ptr); } std::string set(std::string const& value) override { *ptr = value; return ""; } void toVPack(VPackBuilder& builder) const override { builder.add(VPackValue(*ptr)); } ValueType* ptr; }; // specialized type for discrete values (defined in the unordered_set) // this templated type needs a concrete value type template struct DiscreteValuesParameter : public T { DiscreteValuesParameter(typename T::ValueType* ptr, std::unordered_set const& allowed) : T(ptr), allowed(allowed) {} std::string set(std::string const& value) override { auto it = allowed.find(fromString(value)); if (it == allowed.end()) { return "invalid value " + value; } return T::set(value); } std::unordered_set allowed; }; // specialized type for vectors of values // this templated type needs a concrete value type template struct VectorParameter : public Parameter { explicit VectorParameter(std::vector* ptr) : ptr(ptr) {} std::string name() const override { typename T::ValueType dummy; T param(&dummy); return std::string(param.name()) + "..."; } std::string valueString() const override { std::string value; for (size_t i = 0; i < ptr->size(); ++i) { if (i > 0) { value.append(", "); } value.append(stringifyValue(ptr->at(i))); } return value; } std::string set(std::string const& value) override { typename T::ValueType dummy; T param(&dummy); std::string result = param.set(value); if (result.empty()) { ptr->push_back(*(param.ptr)); } return result; } void toVPack(VPackBuilder& builder) const override { builder.openArray(); for (size_t i = 0; i < ptr->size(); ++i) { builder.add(VPackValue(ptr->at(i))); } } std::vector* ptr; }; // a type that's useful for obsolete parameters that do nothing struct ObsoleteParameter : public Parameter { bool requiresValue() const override { return false; } std::string name() const override { return "obsolete"; } std::string valueString() const override { return "-"; } std::string set(std::string const&) override { return ""; } void toVPack(VPackBuilder& builder) const override { builder.add(VPackValue(VPackValueType::Null)); } }; } } #endif