28#include <boost/algorithm/string/join.hpp>
54inline std::string simplify_symbol_variant(
Variant const &v);
57template <
typename T>
auto simplify_symbol(T
const *) {
58 auto constexpr is_string = std::is_same_v<T, std::string>;
61 auto name = (
is_string) ? std::string{
"std::string"} : Utils::demangle<T>();
62 for (std::string::size_type pos{};
71template <
typename T, std::
size_t N>
73 auto const name_val = simplify_symbol(
static_cast<T *
>(
nullptr));
74 return "Utils::Vector<" + Utils::demangle<T>() +
", " + std::to_string(
N) +
79template <
typename T>
auto simplify_symbol(std::vector<T>
const *
vec) {
80 auto const name_val = simplify_symbol(
static_cast<T *
>(
nullptr));
83 metadata +=
"{.size=" + std::to_string(
vec->size()) +
"}";
89inline auto simplify_symbol(std::vector<Variant>
const *
vec) {
93 std::set<std::string>
types = {};
94 for (
auto const &v : *
vec) {
95 types.insert(simplify_symbol_variant(v));
98 metadata +=
"{.size=" + std::to_string(
vec->size()) +
"}";
104template <
typename K,
typename V>
105auto simplify_symbol(std::unordered_map<K, V>
const *) {
106 auto const name_key = simplify_symbol(
static_cast<K *
>(
nullptr));
107 auto const name_val = simplify_symbol(
static_cast<V *
>(
nullptr));
113auto simplify_symbol(std::unordered_map<K, Variant>
const *map) {
114 auto const name_key = simplify_symbol(
static_cast<K *
>(
nullptr));
117 std::set<std::string>
types = {};
126struct simplify_symbol_visitor {
127 template <
class T> std::string operator()(T
const &t)
const {
128 return simplify_symbol(&t);
133inline std::string simplify_symbol_variant(
Variant const &v) {
134 return std::visit(simplify_symbol_visitor(), v);
138template <
typename T>
auto simplify_symbol_containee(T
const *) {
139 return std::string(
"");
143template <
typename T>
auto simplify_symbol_containee(std::vector<T>
const *) {
144 auto const name_val = simplify_symbol(
static_cast<T *
>(
nullptr));
149template <
typename K,
typename V>
150auto simplify_symbol_containee(std::unordered_map<K, V>
const *) {
151 auto const name_key = simplify_symbol(
static_cast<K *
>(
nullptr));
152 auto const name_val = simplify_symbol(
static_cast<V *
>(
nullptr));
156struct simplify_symbol_containee_visitor {
157 template <
class T> std::string operator()(
const T &)
const {
158 return simplify_symbol_containee(
static_cast<T *
>(
nullptr));
166inline auto simplify_symbol_containee_variant(
Variant const &v) {
167 return std::visit(simplify_symbol_containee_visitor(), v);
178template <
class To,
class From>
179using allow_conversion =
180 std::integral_constant<bool, std::is_same_v<To, From> ||
181 (std::is_convertible_v<To, From> &&
182 std::is_floating_point_v<To> &&
183 std::is_arithmetic_v<From>)>;
185template <
class To>
struct conversion_visitor {
186 template <
class From>
To operator()(
const From &value)
const {
187 if constexpr (allow_conversion<To, From>::value) {
190 throw std::bad_variant_access{};
200template <
typename T>
struct get_value_helper {
201 T operator()(
Variant const &v)
const {
202 return std::visit(detail::conversion_visitor<T>(), v);
206template <
class T, std::
size_t N>
struct vector_conversion_visitor {
209 throw std::bad_variant_access{};
212 template <
typename U>
213 requires allow_conversion<T, U>::value
218 template <
typename U>
219 requires(std::is_same_v<U, Variant>
or allow_conversion<T, U>::value)
222 throw std::bad_variant_access{};
224 if constexpr (std::is_same_v<U, Variant>) {
235template <
typename T, std::
size_t N>
236struct get_value_helper<
Utils::Vector<T, N>> {
238 return std::visit(detail::vector_conversion_visitor<T, N>(), v);
242template <
typename T>
struct VisitorVector {
244 template <
typename U> std::vector<T> operator()(
U const &)
const {
245 throw std::bad_variant_access{};
249 std::vector<T> operator()(std::vector<T>
const &v)
const {
return v; }
251 std::vector<T> operator()(std::vector<Variant>
const &
vv)
const
252 requires(
not std::is_same_v<T, Variant>)
254 std::vector<T>
ret(
vv.size());
261 template <
typename U, std::
size_t N>
262 requires allow_conversion<T, U>::value
264 return {
vv.begin(),
vv.end()};
269template <
typename T>
struct get_value_helper<
std::
vector<T>> {
270 std::vector<T> operator()(
Variant const &v)
const {
275template <
typename K,
typename T>
struct VisitorMap {
277 template <
typename U> std::unordered_map<K, T> operator()(
U const &)
const {
278 throw std::bad_variant_access{};
282 auto operator()(std::unordered_map<K, T>
const &map)
const {
return map; }
284 auto operator()(std::unordered_map<K, Variant>
const &map)
const
285 requires(
not std::is_same_v<T, Variant>)
287 std::unordered_map<K, T>
ret;
296template <
typename T>
struct get_value_helper<
std::unordered_map<int, T>> {
297 std::unordered_map<int, T> operator()(
Variant const &v)
const {
302struct get_value_helper<
std::unordered_map<std::string, T>> {
303 std::unordered_map<std::string, T> operator()(
Variant const &v)
const {
309template <>
struct get_value_helper<
std::filesystem::path> {
310 auto operator()(
Variant const &v)
const {
311 if (
auto const *
source = std::get_if<std::string>(&v)) {
312 return std::filesystem::path(*
source);
314 return std::get<std::filesystem::path>(v);
319class bad_get_nullptr :
public std::bad_variant_access {};
326 requires(std::is_base_of_v<ObjectHandle, T>)
327struct get_value_helper<std::shared_ptr<T>> {
328 std::shared_ptr<T> operator()(
Variant const &v)
const {
329 auto so_ptr = std::get<ObjectRef>(v);
331 throw bad_get_nullptr{};
334 if (
auto t_ptr = std::dynamic_pointer_cast<T>(
so_ptr)) {
338 throw std::bad_variant_access{};
350inline void handle_bad_get(
Variant const &v, std::string
const &name) {
352 auto const containee_name = demangle::simplify_symbol_containee_variant(v);
354 demangle::simplify_symbol_containee(
static_cast<T *
>(
nullptr));
358 if (
not name.empty()) {
359 what +=
" for parameter '" + name +
"'";
363 }
catch (bad_get_nullptr
const &) {
365 throw Exception(what +
item_error +
" is a null pointer");
366 }
catch (std::bad_variant_access
const &) {
370 item_error +=
" because it contains a value that";
373 auto const target = demangle::simplify_symbol(
static_cast<T *
>(
nullptr));
378template <
typename T> T get_value(
Variant const &v, std::string
const &name) {
380 return detail::get_value_helper<T>{}(v);
382 detail::handle_bad_get<T>(v, name);
399 return detail::get_value<T>(v,
"");
410 throw Exception(
"Parameter '" + name +
"' is missing.");
412 return detail::get_value<T>(
vals.at(name), name);
422 if (
vals.contains(name)) {
432template <
typename T,
typename...
Types,
typename...
ArgNames>
435 return std::make_shared<T>(
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
T get_value(Variant const &v)
Extract value of specific type T from a Variant.
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.
make_recursive_variant< ObjectRef > 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.
std::vector< T, allocator< T > > vector
Recursive variant implementation.