20#ifndef SCRIPT_INTERFACE_GET_VALUE_HPP
21#define SCRIPT_INTERFACE_GET_VALUE_HPP
29#include <boost/algorithm/string/join.hpp>
30#include <boost/range/algorithm/transform.hpp>
53inline std::string simplify_symbol_variant(
Variant const &v);
56template <
typename T>
auto simplify_symbol(T
const *) {
57 auto constexpr is_string = std::is_same_v<T, std::string>;
58 auto const symbol_for_variant = Utils::demangle<Variant>();
59 auto const name_for_variant = std::string(
"ScriptInterface::Variant");
60 auto name = (is_string) ? std::string{
"std::string"} : Utils::demangle<T>();
61 for (std::string::size_type
pos{};
62 (
pos = name.find(symbol_for_variant,
pos)) != name.npos;
63 pos += name_for_variant.length()) {
64 name.replace(
pos, symbol_for_variant.length(), name_for_variant);
70template <
typename T, std::
size_t N>
72 auto const name_val = simplify_symbol(
static_cast<T *
>(
nullptr));
73 return "Utils::Vector<" + Utils::demangle<T>() +
", " + std::to_string(
N) +
78template <
typename T>
auto simplify_symbol(std::vector<T>
const *vec) {
79 auto const name_val = simplify_symbol(
static_cast<T *
>(
nullptr));
80 std::string metadata{
""};
82 metadata +=
"{.size=" + std::to_string(vec->size()) +
"}";
84 return "std::vector<" + name_val +
">" + metadata;
88inline auto simplify_symbol(std::vector<Variant>
const *vec) {
89 auto value_type_name = std::string(
"ScriptInterface::Variant");
90 std::string metadata{
""};
92 std::set<std::string> types = {};
93 for (
auto const &v : *vec) {
94 types.insert(simplify_symbol_variant(v));
96 value_type_name +=
"{" + boost::algorithm::join(types,
", ") +
"}";
97 metadata +=
"{.size=" + std::to_string(vec->size()) +
"}";
99 return "std::vector<" + value_type_name +
">" + metadata;
103template <
typename K,
typename V>
104auto simplify_symbol(std::unordered_map<K, V>
const *) {
105 auto const name_key = simplify_symbol(
static_cast<K *
>(
nullptr));
106 auto const name_val = simplify_symbol(
static_cast<V *
>(
nullptr));
107 return "std::unordered_map<" + name_key +
", " + name_val +
">";
112auto simplify_symbol(std::unordered_map<K, Variant>
const *map) {
113 auto const name_key = simplify_symbol(
static_cast<K *
>(
nullptr));
114 auto value_type_name = std::string(
"ScriptInterface::Variant");
116 std::set<std::string> types = {};
117 for (
auto const &kv : *map) {
118 types.insert(simplify_symbol_variant(kv.second));
120 value_type_name +=
"{" + boost::algorithm::join(types,
", ") +
"}";
122 return "std::unordered_map<" + name_key +
", " + value_type_name +
">";
125struct simplify_symbol_visitor : boost::static_visitor<std::string> {
126 template <
class T> std::string operator()(T
const &t)
const {
127 return simplify_symbol(&t);
132inline std::string simplify_symbol_variant(
Variant const &v) {
133 return boost::apply_visitor(simplify_symbol_visitor(), v);
137template <
typename T>
auto simplify_symbol_containee(T
const *) {
138 return std::string(
"");
142template <
typename T>
auto simplify_symbol_containee(std::vector<T>
const *) {
143 auto const name_val = simplify_symbol(
static_cast<T *
>(
nullptr));
148template <
typename K,
typename V>
149auto simplify_symbol_containee(std::unordered_map<K, V>
const *) {
150 auto const name_key = simplify_symbol(
static_cast<K *
>(
nullptr));
151 auto const name_val = simplify_symbol(
static_cast<V *
>(
nullptr));
152 return name_key +
"' or '" + name_val;
155struct simplify_symbol_containee_visitor : boost::static_visitor<std::string> {
156 template <
class T> std::string operator()(
const T &)
const {
157 return simplify_symbol_containee(
static_cast<T *
>(
nullptr));
165inline auto simplify_symbol_containee_variant(
Variant const &v) {
166 return boost::apply_visitor(simplify_symbol_containee_visitor(), v);
177template <
class To,
class From>
178using allow_conversion =
179 std::integral_constant<bool, std::is_same_v<To, From> ||
180 (std::is_convertible_v<To, From> &&
181 std::is_floating_point_v<To> &&
182 std::is_arithmetic_v<From>)>;
184template <
class To>
struct conversion_visitor : boost::static_visitor<To> {
185 template <
class From>
186 std::enable_if_t<allow_conversion<To, From>::value, To>
187 operator()(
const From &value)
const {
191 template <
class From>
192 std::enable_if_t<!allow_conversion<To, From>::value, To>
193 operator()(
const From &)
const {
194 throw boost::bad_get{};
204template <
typename T,
typename =
void>
struct get_value_helper {
205 T operator()(
Variant const &v)
const {
206 return boost::apply_visitor(detail::conversion_visitor<T>(), v);
210template <
class T, std::
size_t N>
211struct vector_conversion_visitor : boost::static_visitor<Utils::Vector<T, N>> {
218 auto operator()(std::vector<Variant>
const &vv)
const {
219 if (
N != vv.size()) {
220 throw boost::bad_get{};
224 boost::transform(vv, ret.begin(),
225 [](
const Variant &v) { return get_value_helper<T>{}(v); });
230 template <
typename U>
232 operator()(std::vector<U, std::allocator<U>>
const &v)
const {
234 throw boost::bad_get{};
240 throw boost::bad_get{};
245template <
typename T, std::
size_t N>
246struct get_value_helper<
Utils::Vector<T, N>> {
248 return boost::apply_visitor(detail::vector_conversion_visitor<T, N>(), v);
253struct GetVectorOrEmpty : boost::static_visitor<std::vector<T>> {
255 template <
typename U> std::vector<T> operator()(U
const &)
const {
256 throw boost::bad_get{};
260 std::vector<T> operator()(std::vector<T>
const &v)
const {
return v; }
262 template <
typename V = T,
263 std::enable_if_t<!std::is_same_v<V, Variant>,
bool> =
true>
264 std::vector<T> operator()(std::vector<Variant>
const &vv)
const {
265 std::vector<T> ret(vv.size());
267 boost::transform(vv, ret.begin(),
268 [](
const Variant &v) { return get_value_helper<T>{}(v); });
275template <
typename T>
struct get_value_helper<std::vector<T>, void> {
276 std::vector<T> operator()(Variant
const &v)
const {
277 return boost::apply_visitor(GetVectorOrEmpty<T>(), v);
281template <
typename K,
typename T>
282struct GetMapOrEmpty : boost::static_visitor<std::unordered_map<K, T>> {
284 template <
typename U> std::unordered_map<K, T> operator()(U
const &)
const {
285 throw boost::bad_get{};
289 std::unordered_map<K, T> operator()(std::unordered_map<K, T>
const &v)
const {
293 template <
typename V = T,
294 std::enable_if_t<!std::is_same_v<V, Variant>,
bool> =
true>
295 std::unordered_map<K, T>
296 operator()(std::unordered_map<K, Variant>
const &v)
const {
297 std::unordered_map<K, T> ret;
298 for (
auto it = v.begin(); it != v.end(); ++it) {
299 ret.insert({it->first, get_value_helper<T>{}(it->second)});
307struct get_value_helper<std::unordered_map<int, T>, void> {
308 std::unordered_map<int, T> operator()(Variant
const &v)
const {
309 return boost::apply_visitor(GetMapOrEmpty<int, T>(), v);
313struct get_value_helper<std::unordered_map<std::string, T>, void> {
314 std::unordered_map<std::string, T> operator()(Variant
const &v)
const {
315 return boost::apply_visitor(GetMapOrEmpty<std::string, T>(), v);
320class bad_get_nullptr :
public boost::bad_get {};
327struct get_value_helper<
329 typename std::enable_if_t<std::is_base_of_v<ObjectHandle, T>, void>> {
330 std::shared_ptr<T> operator()(Variant
const &v)
const {
331 auto so_ptr = boost::get<ObjectRef>(v);
333 throw bad_get_nullptr{};
336 auto t_ptr = std::dynamic_pointer_cast<T>(so_ptr);
342 throw boost::bad_get{};
354inline void handle_bad_get(Variant
const &v, std::string
const &name) {
355 auto const container_name = demangle::simplify_symbol_variant(v);
356 auto const containee_name = demangle::simplify_symbol_containee_variant(v);
357 auto const expected_containee_name =
358 demangle::simplify_symbol_containee(
static_cast<T *
>(
nullptr));
359 auto const from_container = !containee_name.empty();
360 auto const to_container = !expected_containee_name.empty();
361 auto what =
"Provided argument of type '" + container_name +
"'";
362 if (not name.empty()) {
363 what +=
" for parameter '" + name +
"'";
367 }
catch (bad_get_nullptr
const &) {
368 auto const item_error = (to_container) ?
" contains a value that" :
"";
369 throw Exception(what + item_error +
" is a null pointer");
370 }
catch (boost::bad_get
const &) {
371 auto const non_convertible = std::string(
" is not convertible to ");
372 auto item_error = std::string(
"");
373 if (from_container and to_container) {
374 item_error +=
" because it contains a value that";
375 item_error += non_convertible +
"'" + expected_containee_name +
"'";
377 auto const target = demangle::simplify_symbol(
static_cast<T *
>(
nullptr));
378 throw Exception(what + non_convertible +
"'" + target +
"'" + item_error);
382template <
typename T> T get_value(Variant
const &v, std::string
const &name) {
384 return detail::get_value_helper<T>{}(v);
386 detail::handle_bad_get<T>(v, name);
402template <
typename T> T get_value(
Variant const &v) {
403 return detail::get_value<T>(v,
"");
412T get_value(
VariantMap const &vals, std::string
const &name) {
413 if (vals.count(name) == 0ul) {
414 throw Exception(
"Parameter '" + name +
"' is missing.");
416 return detail::get_value<T>(vals.at(name), name);
426 if (vals.count(name)) {
427 return get_value<T>(vals.at(name));
436template <
typename T,
typename... Types,
typename... ArgNames>
438 ArgNames &&...args) {
439 return std::make_shared<T>(
440 get_value<Types>(vals, std::forward<ArgNames>(args))...);
445 dst = get_value<T>(vals, name);
__shared__ int pos[MAXDEPTH *THREADS5/WARPSIZE]
std::unordered_map< std::string, Variant > VariantMap
T get_value_or(VariantMap const &vals, std::string const &name, T const &default_)
Get a value from a VariantMap by name, or return a default value if it does not exist.
std::shared_ptr< T > make_shared_from_args(VariantMap const &vals, ArgNames &&...args)
Make a new std::shared_ptr<T> with arguments extracted from a VariantMap.
boost::make_recursive_variant< None, bool, int, std::size_t, double, std::string, ObjectRef, Utils::Vector3b, Utils::Vector3i, Utils::Vector2d, Utils::Vector3d, Utils::Vector4d, std::vector< int >, std::vector< double >, std::vector< boost::recursive_variant_ >, std::unordered_map< int, boost::recursive_variant_ >, std::unordered_map< std::string, boost::recursive_variant_ > >::type Variant
Possible types for parameters.
void set_from_args(T &dst, VariantMap const &vals, const char *name)
std::string demangle()
Get a human-readable name for a type.