Added ScriptValue type as a generic variant type for scripts and similar situations.
This commit is contained in:
parent
3a8602edcc
commit
9b4425c495
208
source/mijin/types/script_value.hpp
Normal file
208
source/mijin/types/script_value.hpp
Normal file
@ -0,0 +1,208 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef MIJIN_TYPES_SCRIPT_VALUE_HPP_INCLUDED
|
||||
#define MIJIN_TYPES_SCRIPT_VALUE_HPP_INCLUDED 1
|
||||
|
||||
#include <charconv>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "../container/optional.hpp"
|
||||
|
||||
namespace mijin
|
||||
{
|
||||
//
|
||||
// public types
|
||||
//
|
||||
|
||||
struct ArrayValue
|
||||
{
|
||||
std::vector<class ScriptValue> values;
|
||||
|
||||
bool operator==(const ArrayValue& other) const;
|
||||
inline bool operator!=(const ArrayValue& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
std::partial_ordering operator<=>(const ArrayValue& other) const;
|
||||
};
|
||||
|
||||
struct UndefinedValue
|
||||
{
|
||||
auto operator<=>(const UndefinedValue&) const = default;
|
||||
};
|
||||
|
||||
inline constexpr UndefinedValue UNDEFINED_VALUE;
|
||||
|
||||
using script_int_t = long long;
|
||||
using script_float_t = double;
|
||||
using script_value_base_t = std::variant<
|
||||
UndefinedValue,
|
||||
bool,
|
||||
script_int_t,
|
||||
script_float_t,
|
||||
std::string,
|
||||
ArrayValue
|
||||
>;
|
||||
|
||||
class ScriptValue
|
||||
{
|
||||
private:
|
||||
script_value_base_t base_;
|
||||
public:
|
||||
ScriptValue() noexcept = default;
|
||||
ScriptValue(const ScriptValue&) noexcept = default;
|
||||
ScriptValue(ScriptValue&&) noexcept = default;
|
||||
template<typename TValue>
|
||||
ScriptValue(TValue&& value);
|
||||
|
||||
ScriptValue& operator=(const ScriptValue&) = default;
|
||||
ScriptValue& operator=(ScriptValue&&) noexcept = default;
|
||||
|
||||
std::partial_ordering operator<=>(const ScriptValue& other) const = default;
|
||||
|
||||
template<typename TFunction>
|
||||
auto visit(TFunction&& function) const
|
||||
{
|
||||
using result_t = std::invoke_result_t<TFunction, long long>;
|
||||
|
||||
if constexpr (std::is_same_v<result_t, void>)
|
||||
{
|
||||
std::visit(function, base_);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::visit(function, base_);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
Optional<script_int_t> toInt() const noexcept
|
||||
{
|
||||
return visit([&](auto&& value) -> Optional<script_int_t>
|
||||
{
|
||||
using type_t = std::decay_t<decltype(value)>;
|
||||
if constexpr (std::is_same_v<type_t, bool> || std::is_same_v<type_t, script_int_t> || std::is_same_v<type_t, script_float_t>)
|
||||
{
|
||||
return static_cast<script_int_t>(value);
|
||||
}
|
||||
else if constexpr (std::is_same_v<type_t, std::string>)
|
||||
{
|
||||
script_int_t result = 0;
|
||||
const std::from_chars_result fromCharsResult = std::from_chars(&*value.begin(), &*value.end(), result);
|
||||
if (fromCharsResult.ec != std::errc{})
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
Optional<script_float_t> toFloat() const noexcept
|
||||
{
|
||||
return visit([&](auto&& value) -> Optional<script_float_t>
|
||||
{
|
||||
using type_t = std::decay_t<decltype(value)>;
|
||||
if constexpr (std::is_same_v<type_t, bool> || std::is_same_v<type_t, script_int_t> || std::is_same_v<type_t, script_float_t>)
|
||||
{
|
||||
return static_cast<script_float_t>(value);
|
||||
}
|
||||
else if constexpr (std::is_same_v<type_t, std::string>)
|
||||
{
|
||||
script_float_t result = 0;
|
||||
const std::from_chars_result fromCharsResult = std::from_chars(&*value.begin(), &*value.end(), result);
|
||||
if (fromCharsResult.ec != std::errc{})
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
Optional<std::string> toString() const noexcept
|
||||
{
|
||||
return visit([](auto&& value) -> Optional<std::string>
|
||||
{
|
||||
using type_t = std::decay_t<decltype(value)>;
|
||||
if constexpr (std::is_same_v<type_t, UndefinedValue>)
|
||||
{
|
||||
return std::string("");
|
||||
}
|
||||
else if constexpr (std::is_same_v<type_t, bool>)
|
||||
{
|
||||
return std::string(value ? "true" : "false");
|
||||
}
|
||||
else if constexpr (std::is_same_v<type_t, script_int_t> || std::is_same_v<type_t, script_float_t>)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
else if constexpr (std::is_same_v<type_t, std::string>)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]]
|
||||
Optional<std::decay_t<T>> to() const noexcept
|
||||
{
|
||||
using type_t = std::decay_t<T>;
|
||||
if constexpr (std::is_same_v<type_t, script_int_t>)
|
||||
{
|
||||
return toInt();
|
||||
}
|
||||
else if constexpr (std::is_integral_v<type_t>)
|
||||
{
|
||||
return toInt().then([](script_int_t val) { return static_cast<type_t>(val); });
|
||||
}
|
||||
else if constexpr (std::is_same_v<type_t, script_float_t>)
|
||||
{
|
||||
return toFloat();
|
||||
}
|
||||
else if constexpr (std::is_floating_point_v<type_t>)
|
||||
{
|
||||
return toFloat().then([](script_float_t val) { return static_cast<type_t>(val); });
|
||||
}
|
||||
else if constexpr (std::is_same_v<type_t, std::string>)
|
||||
{
|
||||
return toString();
|
||||
}
|
||||
else if constexpr (std::is_same_v<type_t, ScriptValue>)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(mijin::always_false_v<T>, "Cannot convert to this type.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// public functions
|
||||
//
|
||||
template<typename TValue>
|
||||
ScriptValue::ScriptValue(TValue&& value) : base_(std::forward<TValue>(value))
|
||||
{
|
||||
}
|
||||
} // namespace mijin
|
||||
|
||||
#endif // MIJIN_TYPES_SCRIPT_VALUE_HPP_INCLUDED
|
||||
Loading…
x
Reference in New Issue
Block a user