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