#pragma once #include #include #include #include enum VariableType { VARTYPE_NULL, VARTYPE_TEXT, VARTYPE_INT, VARTYPE_LONG, VARTYPE_DOUBLE, VARTYPE_FLOAT, VARTYPE_BOOLEAN }; class variable; namespace typecast { template struct FalseType : std::false_type {}; template inline T variable_cast(const variable& in) { static_assert( FalseType::value , "this function has to be implemented for desired type"); return nullptr; }; //str to type template inline std::string variable_cast(T& in) { static_assert( FalseType::value , "this function has to be implemented for desired type"); return "undefined"; }; //type to str template inline VariableType variable_type() { static_assert( FalseType::value , "this function has to be implemented for desired type"); return VARTYPE_NULL; }; //type to str } struct variable_data { variable_data(const std::pair &pair, VariableType _type); ~variable_data() = default; std::pair pair; VariableType _type; }; class variable { public: variable() noexcept : data(std::make_shared(std::pair{"", ""}, VariableType::VARTYPE_NULL)) {} variable(const std::string& key) noexcept : variable() { r_key() = key; } variable(const std::string& key, const variable& value) noexcept : variable(key) { this->r_value() = value.string(); this->data->pair.second = value.string(); } variable(const std::string& key, const std::string& value, VariableType type) noexcept : data(std::make_shared(std::pair{key, value}, VariableType::VARTYPE_TEXT)) {} variable(const variable& ref) : data(ref.data) {} variable(variable&& ref) : data(ref.data) { } virtual ~variable() = default; template variable(const std::string& key, T value) : variable(key) { operator=(value); } variable& operator=(const variable& ref); variable& operator=(variable&& ref); std::string key() const { return data->pair.first; } std::string value() const { return data->pair.second; } VariableType type() const { return data->_type; } variable clone(){ return variable(key(), value(), type()); } variable(std::string key, std::nullptr_t) : variable() { r_key() = std::move(key); data->_type = VariableType ::VARTYPE_NULL; } explicit variable(std::nullptr_t) noexcept : variable() { data->_type = VariableType ::VARTYPE_NULL; } variable&operator=(std::nullptr_t) { r_value() = ""; data->_type = VARTYPE_NULL; return *this;} template T as() const { return typecast::variable_cast(*this); } std::string string() const { return as(); } //fast template //TODO more secure and not just try and fail bool castable() { try { as(); return true; } catch (...) { return false; } } template variable& operator=(T obj){ r_value() = typecast::variable_cast(obj); data->_type = typecast::variable_type(); return *this; } template operator T() const { return as(); } private: std::string& r_key() const { return data->pair.first; } std::string& r_value() const { return data->pair.second; } std::shared_ptr data; }; #define DEFINE_VARIABLE_TRANSFORM_TO_STR(type, to_str) \ namespace typecast { \ template <> \ inline std::string variable_cast(type& in) { return to_str; } \ } #define DEFINE_VARIABLE_TRANSFORM_TO_VAR(type, from_str) \ namespace typecast { \ template <> \ inline type variable_cast(const variable& in) { return from_str; } \ } #define DEFINE_VARIABLE_TRANSFORM_TYPE(type, vartype) \ namespace typecast { \ template <> \ inline VariableType variable_type() { return VariableType::vartype; } \ } #define DEFINE_VARIABLE_TRANSFORM(type, ntype, to_str, from_str) \ DEFINE_VARIABLE_TRANSFORM_TO_STR(type, to_str); \ DEFINE_VARIABLE_TRANSFORM_TO_VAR(type, from_str) \ DEFINE_VARIABLE_TRANSFORM_TYPE(type, ntype) #define DEFINE_VARIABLE_TRANSFORM_ENUM(class, size_type) \ DEFINE_VARIABLE_TRANSFORM(class, VARTYPE_INT, std::to_string((size_type) in), static_cast(in.as())); DEFINE_VARIABLE_TRANSFORM(std::string, VARTYPE_TEXT, in, in.value()); DEFINE_VARIABLE_TRANSFORM(char*, VARTYPE_TEXT, std::string((const char*) in), (char*) in.value().c_str()); DEFINE_VARIABLE_TRANSFORM(const char*, VARTYPE_TEXT, std::string((const char*) in), in.value().c_str()); DEFINE_VARIABLE_TRANSFORM(int8_t, VARTYPE_INT, std::to_string(in), std::stoi(in.value())); DEFINE_VARIABLE_TRANSFORM(uint8_t, VARTYPE_INT, std::to_string(in), std::stoul(in.value())); DEFINE_VARIABLE_TRANSFORM(int16_t, VARTYPE_INT, std::to_string(in), std::stoi(in.value())); DEFINE_VARIABLE_TRANSFORM(uint16_t, VARTYPE_INT, std::to_string(in), std::stoul(in.value())); DEFINE_VARIABLE_TRANSFORM(int32_t, VARTYPE_INT, std::to_string(in), std::stoi(in.value())); DEFINE_VARIABLE_TRANSFORM(uint32_t, VARTYPE_INT, std::to_string(in), std::stoul(in.value())); DEFINE_VARIABLE_TRANSFORM(int64_t, VARTYPE_LONG, std::to_string(in), std::stoll(in.value())); DEFINE_VARIABLE_TRANSFORM(uint64_t, VARTYPE_LONG, std::to_string(in), std::stoull(in.value())); DEFINE_VARIABLE_TRANSFORM(bool, VARTYPE_INT, in ? "1" : "0", in.value() == "1"); DEFINE_VARIABLE_TRANSFORM(double, VARTYPE_DOUBLE, std::to_string(in), std::stod(in.value())); DEFINE_VARIABLE_TRANSFORM(float, VARTYPE_FLOAT, std::to_string(in), std::stof(in.value()));