From 55ddd8c2c32b40f096d22d3f319cd7942eab6db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Micha=C3=ABl=20Celerier?= Date: Sun, 29 Sep 2024 23:02:10 -0400 Subject: [PATCH] [max/pd] Handle even more types --- examples/Raw/AllPortsTypes.hpp | 127 ++++++++++++- include/avnd/binding/max/attributes_setup.hpp | 56 +++++- include/avnd/binding/max/from_atoms.hpp | 20 ++- include/avnd/binding/max/helpers.hpp | 7 +- include/avnd/binding/max/init.hpp | 2 +- include/avnd/binding/max/outputs.hpp | 141 +++++++++++---- include/avnd/binding/max/to_atoms.hpp | 109 +++++++---- include/avnd/binding/pd/construct.hpp | 2 +- include/avnd/binding/pd/helpers.hpp | 8 +- include/avnd/binding/pd/init.hpp | 2 +- include/avnd/binding/pd/inputs.hpp | 20 ++- include/avnd/binding/pd/outputs.hpp | 169 +++++++++++++----- include/avnd/concepts/generic.hpp | 28 +-- 13 files changed, 553 insertions(+), 138 deletions(-) diff --git a/examples/Raw/AllPortsTypes.hpp b/examples/Raw/AllPortsTypes.hpp index 5764f498..78f232b7 100644 --- a/examples/Raw/AllPortsTypes.hpp +++ b/examples/Raw/AllPortsTypes.hpp @@ -54,8 +54,10 @@ struct AllPortsTypes static consteval auto c_name() { return "avnd_all_ports_types"; } static consteval auto uuid() { return "7713f267-4ced-4bf0-87d6-f56e368c2be8"; } - struct + // clang-format off + struct inputs { +#if 1 struct { static constexpr auto name() { return "float"; } float value; } p_float; struct { static constexpr auto name() { return "double"; } double value; } p_double; struct { static constexpr auto name() { return "int"; } int value; } p_int; @@ -82,14 +84,14 @@ struct AllPortsTypes struct { static constexpr auto name() { return "vector_string"; } std::vector value; } p_vector_string; struct { static constexpr auto name() { return "vector_enum"; } std::vector value; } p_vector_enum; struct { static constexpr auto name() { return "vector_agg"; } std::vector value; } p_vector_agg; -/* + struct { static constexpr auto name() { return "list_float"; } std::listvalue; } p_list_float; struct { static constexpr auto name() { return "list_double"; } std::listvalue; } p_list_double; struct { static constexpr auto name() { return "list_int"; } std::listvalue; } p_list_int; struct { static constexpr auto name() { return "list_string"; } std::list value; } p_list_string; struct { static constexpr auto name() { return "list_enum"; } std::list value; } p_list_enum; struct { static constexpr auto name() { return "list_agg"; } std::list value; } p_list_agg; -*/ + struct { static constexpr auto name() { return "deque_float"; } std::dequevalue; } p_deque_float; struct { static constexpr auto name() { return "deque_double"; } std::dequevalue; } p_deque_double; struct { static constexpr auto name() { return "deque_int"; } std::dequevalue; } p_deque_int; @@ -166,11 +168,124 @@ struct AllPortsTypes struct { static constexpr auto name() { return "umap_int_string"; } std::unordered_map value; } p_umap_int_string; struct { static constexpr auto name() { return "umap_int_enum"; } std::unordered_map value; } p_umap_int_enum; struct { static constexpr auto name() { return "umap_int_agg"; } std::unordered_map value; } p_umap_int_agg; + #endif + +#if 0 + struct {enum { class_attribute }; static constexpr auto symbol() { return "float"; } static constexpr auto name() { return "float"; } float value; } p_symbol_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "double"; } static constexpr auto name() { return "double"; } double value; } p_symbol_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "int"; } static constexpr auto name() { return "int"; } int value; } p_symbol_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "string"; } static constexpr auto name() { return "string"; } std::string value; } p_symbol_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "enum"; } static constexpr auto name() { return "enum"; } Foo value; } p_symbol_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "agg"; } static constexpr auto name() { return "agg"; } Aggregate value; } p_symbol_agg; + struct {enum { class_attribute }; static constexpr auto symbol() { return "bitset"; } static constexpr auto name() { return "bitset"; } std::bitset<53> value; } p_symbol_bitset; + struct {enum { class_attribute }; static constexpr auto symbol() { return "pair_int_int"; } static constexpr auto name() { return "pair_int_int"; } std::pair value; } p_symbol_pair_int_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "pair_float_string"; } static constexpr auto name() { return "pair_float_string"; } std::pair value; } p_symbol_pair_float_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "tuple_int_int"; } static constexpr auto name() { return "tuple_int_int"; } std::tuple value; } p_symbol_tuple_int_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "tuple_float_string"; } static constexpr auto name() { return "tuple_float_string"; } std::tuple value; } p_symbol_tuple_float_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "variant"; } static constexpr auto name() { return "variant"; } std::variant value; } p_symbol_variant; + + struct {enum { class_attribute }; static constexpr auto symbol() { return "optional_float"; } static constexpr auto name() { return "optional_float"; } std::optionalvalue; } p_symbol_optional_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "optional_double"; } static constexpr auto name() { return "optional_double"; } std::optionalvalue; } p_symbol_optional_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "optional_int"; } static constexpr auto name() { return "optional_int"; } std::optionalvalue; } p_symbol_optional_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "optional_string"; } static constexpr auto name() { return "optional_string"; } std::optional value; } p_symbol_optional_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "optional_enum"; } static constexpr auto name() { return "optional_enum"; } std::optional value; } p_symbol_optional_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "optional_agg"; } static constexpr auto name() { return "optional_agg"; } std::optional value; } p_symbol_optional_agg; + + struct {enum { class_attribute }; static constexpr auto symbol() { return "vector_float"; } static constexpr auto name() { return "vector_float"; } std::vectorvalue; } p_symbol_vector_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "vector_double"; } static constexpr auto name() { return "vector_double"; } std::vectorvalue; } p_symbol_vector_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "vector_int"; } static constexpr auto name() { return "vector_int"; } std::vectorvalue; } p_symbol_vector_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "vector_string"; } static constexpr auto name() { return "vector_string"; } std::vector value; } p_symbol_vector_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "vector_enum"; } static constexpr auto name() { return "vector_enum"; } std::vector value; } p_symbol_vector_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "vector_agg"; } static constexpr auto name() { return "vector_agg"; } std::vector value; } p_symbol_vector_agg; + + struct {enum { class_attribute }; static constexpr auto symbol() { return "list_float"; } static constexpr auto name() { return "list_float"; } std::listvalue; } p_symbol_list_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "list_double"; } static constexpr auto name() { return "list_double"; } std::listvalue; } p_symbol_list_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "list_int"; } static constexpr auto name() { return "list_int"; } std::listvalue; } p_symbol_list_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "list_string"; } static constexpr auto name() { return "list_string"; } std::list value; } p_symbol_list_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "list_enum"; } static constexpr auto name() { return "list_enum"; } std::list value; } p_symbol_list_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "list_agg"; } static constexpr auto name() { return "list_agg"; } std::list value; } p_symbol_list_agg; + + struct {enum { class_attribute }; static constexpr auto symbol() { return "deque_float"; } static constexpr auto name() { return "deque_float"; } std::dequevalue; } p_symbol_deque_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "deque_double"; } static constexpr auto name() { return "deque_double"; } std::dequevalue; } p_symbol_deque_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "deque_int"; } static constexpr auto name() { return "deque_int"; } std::dequevalue; } p_symbol_deque_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "deque_string"; } static constexpr auto name() { return "deque_string"; } std::deque value; } p_symbol_deque_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "deque_enum"; } static constexpr auto name() { return "deque_enum"; } std::deque value; } p_symbol_deque_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "deque_agg"; } static constexpr auto name() { return "deque_agg"; } std::deque value; } p_symbol_deque_agg; + + struct {enum { class_attribute }; static constexpr auto symbol() { return "bvector_float"; } static constexpr auto name() { return "bvector_float"; } boost::container::vectorvalue; } p_symbol_bvector_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "bvector_double"; } static constexpr auto name() { return "bvector_double"; } boost::container::vectorvalue; } p_symbol_bvector_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "bvector_int"; } static constexpr auto name() { return "bvector_int"; } boost::container::vectorvalue; } p_symbol_bvector_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "bvector_string"; } static constexpr auto name() { return "bvector_string"; } boost::container::vector value; } p_symbol_bvector_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "bvector_enum"; } static constexpr auto name() { return "bvector_enum"; } boost::container::vector value; } p_symbol_bvector_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "bvector_agg"; } static constexpr auto name() { return "bvector_agg"; } boost::container::vector value; } p_symbol_bvector_agg; + + struct {enum { class_attribute }; static constexpr auto symbol() { return "array_float"; } static constexpr auto name() { return "array_float"; } std::arrayvalue; } p_symbol_array_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "array_double"; } static constexpr auto name() { return "array_double"; } std::arrayvalue; } p_symbol_array_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "array_int"; } static constexpr auto name() { return "array_int"; } std::arrayvalue; } p_symbol_array_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "array_string"; } static constexpr auto name() { return "array_string"; } std::array value; } p_symbol_array_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "array_enum"; } static constexpr auto name() { return "array_enum"; } std::array value; } p_symbol_array_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "array_agg"; } static constexpr auto name() { return "array_agg"; } std::array value; } p_symbol_array_agg; + + struct {enum { class_attribute }; static constexpr auto symbol() { return "smallvec_float"; } static constexpr auto name() { return "smallvec_float"; } boost::container::small_vectorvalue; } p_symbol_smallvec_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "smallvec_double"; } static constexpr auto name() { return "smallvec_double"; } boost::container::small_vectorvalue; } p_symbol_smallvec_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "smallvec_int"; } static constexpr auto name() { return "smallvec_int"; } boost::container::small_vectorvalue; } p_symbol_smallvec_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "smallvec_string"; } static constexpr auto name() { return "smallvec_string"; } boost::container::small_vector value; } p_symbol_smallvec_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "smallvec_enum"; } static constexpr auto name() { return "smallvec_enum"; } boost::container::small_vector value; } p_symbol_smallvec_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "smallvec_agg"; } static constexpr auto name() { return "smallvec_agg"; } boost::container::small_vector value; } p_symbol_smallvec_agg; + + struct {enum { class_attribute }; static constexpr auto symbol() { return "staticvec_float"; } static constexpr auto name() { return "staticvec_float"; } boost::container::static_vectorvalue; } p_symbol_staticvec_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "staticvec_double"; } static constexpr auto name() { return "staticvec_double"; } boost::container::static_vectorvalue; } p_symbol_staticvec_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "staticvec_int"; } static constexpr auto name() { return "staticvec_int"; } boost::container::static_vectorvalue; } p_symbol_staticvec_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "staticvec_string"; } static constexpr auto name() { return "staticvec_string"; } boost::container::static_vector value; } p_symbol_staticvec_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "staticvec_enum"; } static constexpr auto name() { return "staticvec_enum"; } boost::container::static_vector value; } p_symbol_staticvec_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "staticvec_agg"; } static constexpr auto name() { return "staticvec_agg"; } boost::container::static_vector value; } p_symbol_staticvec_agg; + + struct {enum { class_attribute }; static constexpr auto symbol() { return "set_float"; } static constexpr auto name() { return "set_float"; } std::setvalue; } p_symbol_set_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "set_double"; } static constexpr auto name() { return "set_double"; } std::setvalue; } p_symbol_set_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "set_int"; } static constexpr auto name() { return "set_int"; } std::setvalue; } p_symbol_set_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "set_string"; } static constexpr auto name() { return "set_string"; } std::set value; } p_symbol_set_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "set_enum"; } static constexpr auto name() { return "set_enum"; } std::set value; } p_symbol_set_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "set_agg"; } static constexpr auto name() { return "set_agg"; } std::set value; } p_symbol_set_agg; + + struct {enum { class_attribute }; static constexpr auto symbol() { return "uset_float"; } static constexpr auto name() { return "uset_float"; } std::unordered_setvalue; } p_symbol_uset_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "uset_double"; } static constexpr auto name() { return "uset_double"; } std::unordered_setvalue; } p_symbol_uset_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "uset_int"; } static constexpr auto name() { return "uset_int"; } std::unordered_setvalue; } p_symbol_uset_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "uset_string"; } static constexpr auto name() { return "uset_string"; } std::unordered_set value; } p_symbol_uset_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "uset_enum"; } static constexpr auto name() { return "uset_enum"; } std::unordered_set value; } p_symbol_uset_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "uset_agg"; } static constexpr auto name() { return "uset_agg"; } std::unordered_set value; } p_symbol_uset_agg; + + struct {enum { class_attribute }; static constexpr auto symbol() { return "map_string_float"; } static constexpr auto name() { return "map_string_float"; } std::mapvalue; } p_symbol_map_string_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "map_string_double"; } static constexpr auto name() { return "map_string_double"; } std::mapvalue; } p_symbol_map_string_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "map_string_int"; } static constexpr auto name() { return "map_string_int"; } std::mapvalue; } p_symbol_map_string_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "map_string_string"; } static constexpr auto name() { return "map_string_string"; } std::map value; } p_symbol_map_string_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "map_string_enum"; } static constexpr auto name() { return "map_string_enum"; } std::map value; } p_symbol_map_string_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "map_string_agg"; } static constexpr auto name() { return "map_string_agg"; } std::map value; } p_symbol_map_string_agg; + + struct {enum { class_attribute }; static constexpr auto symbol() { return "map_int_float"; } static constexpr auto name() { return "map_int_float"; } std::mapvalue; } p_symbol_map_int_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "map_int_double"; } static constexpr auto name() { return "map_int_double"; } std::mapvalue; } p_symbol_map_int_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "map_int_int"; } static constexpr auto name() { return "map_int_int"; } std::mapvalue; } p_symbol_map_int_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "map_int_string"; } static constexpr auto name() { return "map_int_string"; } std::map value; } p_symbol_map_int_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "map_int_enum"; } static constexpr auto name() { return "map_int_enum"; } std::map value; } p_symbol_map_int_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "map_int_agg"; } static constexpr auto name() { return "map_int_agg"; } std::map value; } p_symbol_map_int_agg; + + struct {enum { class_attribute }; static constexpr auto symbol() { return "umap_string_float"; } static constexpr auto name() { return "umap_string_float"; } std::unordered_mapvalue; } p_symbol_umap_string_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "umap_string_double"; } static constexpr auto name() { return "umap_string_double"; } std::unordered_mapvalue; } p_symbol_umap_string_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "umap_string_int"; } static constexpr auto name() { return "umap_string_int"; } std::unordered_mapvalue; } p_symbol_umap_string_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "umap_string_string"; } static constexpr auto name() { return "umap_string_string"; } std::unordered_map value; } p_symbol_umap_string_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "umap_string_enum"; } static constexpr auto name() { return "umap_string_enum"; } std::unordered_map value; } p_symbol_umap_string_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "umap_string_agg"; } static constexpr auto name() { return "umap_string_agg"; } std::unordered_map value; } p_symbol_umap_string_agg; + + struct {enum { class_attribute }; static constexpr auto symbol() { return "umap_int_float"; } static constexpr auto name() { return "umap_int_float"; } std::unordered_mapvalue; } p_symbol_umap_int_float; + struct {enum { class_attribute }; static constexpr auto symbol() { return "umap_int_double"; } static constexpr auto name() { return "umap_int_double"; } std::unordered_mapvalue; } p_symbol_umap_int_double; + struct {enum { class_attribute }; static constexpr auto symbol() { return "umap_int_int"; } static constexpr auto name() { return "umap_int_int"; } std::unordered_mapvalue; } p_symbol_umap_int_int; + struct {enum { class_attribute }; static constexpr auto symbol() { return "umap_int_string"; } static constexpr auto name() { return "umap_int_string"; } std::unordered_map value; } p_symbol_umap_int_string; + struct {enum { class_attribute }; static constexpr auto symbol() { return "umap_int_enum"; } static constexpr auto name() { return "umap_int_enum"; } std::unordered_map value; } p_symbol_umap_int_enum; + struct {enum { class_attribute }; static constexpr auto symbol() { return "umap_int_agg"; } static constexpr auto name() { return "umap_int_agg"; } std::unordered_map value; } p_symbol_umap_int_agg; +#endif + // clang-format on } inputs; - struct - { - } outputs; + struct inputs outputs; void operator()() { } }; diff --git a/include/avnd/binding/max/attributes_setup.hpp b/include/avnd/binding/max/attributes_setup.hpp index 8a7bbac1..86195f16 100644 --- a/include/avnd/binding/max/attributes_setup.hpp +++ b/include/avnd/binding/max/attributes_setup.hpp @@ -137,20 +137,70 @@ struct attribute_object_register template void operator()(F& field, avnd::predicate_index) { + using value_type = std::remove_cvref_t; static const auto attr_name = max::symbol_from_name(); - if constexpr(std::is_integral_v) + if constexpr(std::is_integral_v) { object_attr_setlong(o, attr_name, field.value); } - else if constexpr(std::is_floating_point_v) + else if constexpr(std::is_floating_point_v) { object_attr_setfloat(o, attr_name, field.value); } - else if constexpr(avnd::string_ish) + else if constexpr(avnd::string_ish) { object_attr_setsym(o, attr_name, gensym(field.value.data())); } + else if constexpr(std::is_enum_v) + { + object_attr_setsym( + o, attr_name, gensym(magic_enum::enum_name(field.value).data())); + } + else if constexpr(avnd::iterable_ish) + { + using span_val_type = typename value_type::value_type; + + if constexpr(std::is_integral_v) + { + using namespace std; + boost::container::small_vector vec; + vec.assign(begin(field.value), end(field.value)); + object_attr_setlong_array(o, attr_name, vec.size(), vec.data()); + } + else if constexpr(std::is_same_v) + { + using namespace std; + boost::container::small_vector vec; + vec.assign(begin(field.value), end(field.value)); + object_attr_setfloat_array(o, attr_name, vec.size(), vec.data()); + } + else if constexpr(std::is_floating_point_v) + { + using namespace std; + boost::container::small_vector vec; + vec.assign(begin(field.value), end(field.value)); + object_attr_setdouble_array(o, attr_name, vec.size(), vec.data()); + } + else if constexpr(avnd::string_ish) + { + boost::container::small_vector vec; + for(auto& v : field.value) + vec.push_back(gensym(v.data())); + object_attr_setsym_array(o, attr_name, vec.size(), vec.data()); + } + else if constexpr(std::is_enum_v) + { + boost::container::small_vector vec; + for(auto& v : field.value) + vec.push_back(gensym(magic_enum::enum_name(v).data())); + object_attr_setsym_array(o, attr_name, vec.size(), vec.data()); + } + else + { + static_assert(F::error_in_attribute, "Unhandled attribute type"); + } + } else { static_assert(F::error_in_attribute, "Unhandled attribute type"); diff --git a/include/avnd/binding/max/from_atoms.hpp b/include/avnd/binding/max/from_atoms.hpp index d19e7fd3..bad3a9d7 100644 --- a/include/avnd/binding/max/from_atoms.hpp +++ b/include/avnd/binding/max/from_atoms.hpp @@ -25,7 +25,7 @@ struct from_atom requires std::is_aggregate_v bool operator()(T& v) const noexcept = delete; - bool operator()(avnd::span_ish auto& v) const noexcept = delete; + bool operator()(avnd::iterable_ish auto& v) const noexcept = delete; bool operator()(avnd::pair_ish auto& v) const noexcept = delete; bool operator()(avnd::tuple_ish auto& v) const noexcept = delete; bool operator()(avnd::map_ish auto& v) const noexcept = delete; @@ -156,6 +156,20 @@ struct from_atoms return res; } + template + bool operator()(T& v) const noexcept + { + v.clear(); + + for(int i = 0; i < ac; i++) + { + typename T::value_type item; + from_atom{av[i]}(item); + v.push_back(std::move(item)); + } + return true; + } + bool operator()(avnd::vector_ish auto& v) const noexcept { v.clear(); @@ -308,7 +322,9 @@ struct from_atoms } template - requires(std::is_aggregate_v && !avnd::span_ish && avnd::pfr::tuple_size_v > 0) + requires( + std::is_aggregate_v && !avnd::iterable_ish + && avnd::pfr::tuple_size_v > 0) bool operator()(T& v) const noexcept { avnd::for_each_field_ref(v, [this, i = 0] (F& field) mutable { diff --git a/include/avnd/binding/max/helpers.hpp b/include/avnd/binding/max/helpers.hpp index 2098b4fe..e217c817 100644 --- a/include/avnd/binding/max/helpers.hpp +++ b/include/avnd/binding/max/helpers.hpp @@ -24,18 +24,21 @@ concept convertible_to_fundamental_value_type template struct convertible_to_fundamental_value_type_pred : std::bool_constant>{}; +// clang-format off template concept convertible_to_atom_list_statically_impl = convertible_to_fundamental_value_type || (avnd::bitset_ish) || - (avnd::span_ish && convertible_to_fundamental_value_type) || + (avnd::iterable_ish && convertible_to_fundamental_value_type) || (avnd::pair_ish && convertible_to_fundamental_value_type && convertible_to_fundamental_value_type) || + (avnd::set_ish && convertible_to_fundamental_value_type && convertible_to_fundamental_value_type) || (avnd::map_ish && convertible_to_fundamental_value_type && convertible_to_fundamental_value_type) || (avnd::optional_ish && convertible_to_fundamental_value_type) || (avnd::variant_ish && boost::mp11::mp_all_of::value) || (avnd::tuple_ish && boost::mp11::mp_all_of::value) || - (std::is_aggregate_v && !avnd::span_ish && boost::mp11::mp_all_of, convertible_to_fundamental_value_type_pred>::value) + (std::is_aggregate_v && !avnd::iterable_ish && boost::mp11::mp_all_of, convertible_to_fundamental_value_type_pred>::value) ; +// clang-format on template concept convertible_to_atom_list_statically = convertible_to_atom_list_statically_impl>; diff --git a/include/avnd/binding/max/init.hpp b/include/avnd/binding/max/init.hpp index 26aa6e3e..d98eb178 100644 --- a/include/avnd/binding/max/init.hpp +++ b/include/avnd/binding/max/init.hpp @@ -125,7 +125,7 @@ struct init_arguments call_vec(implementation, name, argc, argv); return; } - else if constexpr(avnd::span_ish) + else if constexpr(avnd::iterable_ish) { call_span(implementation, name, argc, argv); return; diff --git a/include/avnd/binding/max/outputs.hpp b/include/avnd/binding/max/outputs.hpp index 52ab14b0..8f40571e 100644 --- a/include/avnd/binding/max/outputs.hpp +++ b/include/avnd/binding/max/outputs.hpp @@ -36,6 +36,12 @@ inline void value_to_max(t_atom& atom, const std::string& v) noexcept { atom = {.a_type = A_SYM, .a_w = {.w_sym = gensym(v.c_str())}}; } +template + requires std::is_enum_v +inline void value_to_max(t_atom& atom, T v) noexcept +{ + atom = {.a_type = A_SYM, .a_w = {.w_sym = gensym(magic_enum::enum_name(v).data())}}; +} struct do_value_to_max_rec { @@ -43,7 +49,7 @@ struct do_value_to_max_rec boost::container::small_vector atoms; template - requires(std::is_aggregate_v && !avnd::span_ish && !avnd::tuple_ish) + requires(std::is_aggregate_v && !avnd::iterable_ish && !avnd::tuple_ish) void operator()(const T& v) { avnd::for_each_field_ref_n( @@ -72,6 +78,13 @@ struct do_value_to_max_rec { atoms.push_back({.a_type = A_SYM, .a_w = {.w_sym = gensym(v.data())}}); } + template + requires std::is_enum_v + void operator()(T v) noexcept + { + atoms.push_back( + {.a_type = A_SYM, .a_w = {.w_sym = gensym(magic_enum::enum_name(v).data())}}); + } void operator()(const avnd::iterable_ish auto& v) noexcept { @@ -98,6 +111,12 @@ struct do_value_to_max_rec visit([this](const auto& val) { (*this)(val); }, v); } + void operator()(const avnd::optional_ish auto& v) noexcept + { + if(v) + (*this)(*v); + } + void operator()(const avnd::pair_ish auto& v) noexcept { (*this)(v.first); @@ -132,6 +151,14 @@ struct do_value_to_max_typed { outlet_int(p, v); } + template + requires std::is_enum_v + void operator()(T v) const noexcept + { + t_atom atom; + value_to_max(atom, v); + outlet_anything(p, _sym_symbol, 1, &atom); + } void operator()(std::string_view v) const noexcept { outlet_anything(p, gensym(v.data()), 0, nullptr); @@ -142,7 +169,7 @@ struct do_value_to_max_typed } template - requires(std::is_aggregate_v && !avnd::span_ish && !avnd::tuple_ish) + requires(std::is_aggregate_v && !avnd::iterable_ish && !avnd::tuple_ish) void operator()(const T& v) const noexcept { to_list l; @@ -155,7 +182,7 @@ struct do_value_to_max_typed } template - void operator()(const avnd::array_ish auto& v) + void operator()(const avnd::array_ish auto& v) const noexcept { std::array atoms; @@ -166,7 +193,7 @@ struct do_value_to_max_typed outlet_list(p, nullptr, N, atoms.data()); } - void operator()(const avnd::span_ish auto& v) const noexcept + void operator()(const avnd::iterable_ish auto& v) const noexcept { to_list l; l(v); @@ -187,6 +214,12 @@ struct do_value_to_max_typed outlet_list(p, nullptr, l.atoms.size(), l.atoms.data()); } + void operator()(const avnd::optional_ish auto& v) const noexcept + { + if(v) + (*this)(*v); + } + void operator()(const avnd::variant_ish auto& v) const noexcept { using namespace std; @@ -200,9 +233,49 @@ struct do_value_to_max_typed outlet_list(p, nullptr, l.atoms.size(), l.atoms.data()); } + template + requires avnd::pair_ish + void operator()(const T& v) const noexcept + { + t_atom atoms[2]; + + value_to_max(atoms[0], v.first); + value_to_max(atoms[1], v.second); + + outlet_list(p, nullptr, 2, atoms); + } + + template + requires(!avnd::iterable_ish && !avnd::pair_ish) + void operator()(const T& v) const noexcept + { + static constexpr int N = std::tuple_size_v; + std::array atoms; + + [&](std::index_sequence) { + (set_atom{}(&atoms[I], std::get(v)), ...); + }(std::make_index_sequence{}); + + outlet_list(p, nullptr, N, atoms.data()); + } + + void operator()(const avnd::bitset_ish auto& v) const noexcept + { + boost::container::small_vector atoms; + const int N = v.size(); + atoms.resize(2 * N); + + for(int i = 0, N = v.size(); i < N; i++) + { + value_to_max(atoms[i], v.test(i) ? 1 : 0); + } + + outlet_list(p, nullptr, atoms.size(), atoms.data()); + } + template requires(sizeof...(Args) > 1) - void operator()(Args&&... v) noexcept + void operator()(Args&&... v) const noexcept { std::array atoms; static constexpr int N = sizeof...(Args); @@ -248,9 +321,17 @@ struct do_value_to_max_anything value_to_max(atom, v); outlet_anything(p, s, 1, &atom); } + template + requires std::is_enum_v + void operator()(T v) const noexcept + { + t_atom atom; + value_to_max(atom, v); + outlet_anything(p, s, 1, &atom); + } template - requires(std::is_aggregate_v && !avnd::span_ish && !avnd::tuple_ish) + requires(std::is_aggregate_v && !avnd::iterable_ish && !avnd::tuple_ish) void operator()(const T& v) const noexcept { to_list l; @@ -263,7 +344,7 @@ struct do_value_to_max_anything } template - void operator()(const avnd::array_ish auto& v) + void operator()(const avnd::array_ish auto& v) const noexcept { std::array atoms; @@ -275,7 +356,8 @@ struct do_value_to_max_anything } template - void operator()(const T& v) + requires(!avnd::iterable_ish && !avnd::pair_ish) + void operator()(const T& v) const noexcept { static constexpr auto N = std::tuple_size_v; std::array atoms; @@ -287,21 +369,7 @@ struct do_value_to_max_anything outlet_anything(p, s, N, atoms.data()); } - void operator()(const avnd::span_ish auto& v) const noexcept - { - to_list l; - l(v); - outlet_anything(p, s, l.atoms.size(), l.atoms.data()); - } - - void operator()(const avnd::vector_ish auto& v) const noexcept - { - to_list l; - l(v); - outlet_anything(p, s, l.atoms.size(), l.atoms.data()); - } - - void operator()(const avnd::set_ish auto& v) const noexcept + void operator()(const avnd::iterable_ish auto& v) const noexcept { to_list l; l(v); @@ -314,16 +382,15 @@ struct do_value_to_max_anything visit([this](const auto& val) { (*this)(val); }, v); } - void operator()(const avnd::map_ish auto& v) const noexcept + void operator()(const avnd::optional_ish auto& v) const noexcept { - to_list l; - l(v); - outlet_anything(p, s, l.atoms.size(), l.atoms.data()); + if(v) + (*this)(*v); } template requires avnd::pair_ish - void operator()(const T& v) + void operator()(const T& v) const noexcept { t_atom atoms[2]; @@ -333,12 +400,26 @@ struct do_value_to_max_anything outlet_anything(p, s, 2, atoms); } + void operator()(const avnd::bitset_ish auto& v) const noexcept + { + boost::container::small_vector atoms; + const int N = v.size(); + atoms.resize(2 * N); + + for(int i = 0, N = v.size(); i < N; i++) + { + value_to_max(atoms[i], v.test(i) ? 1 : 0); + } + + outlet_anything(p, s, atoms.size(), atoms.data()); + } + template - void operator()(t_outlet*, Args&&... v) noexcept = delete; + void operator()(t_outlet*, Args&&... v) const noexcept = delete; template requires(sizeof...(Args) > 1) - void operator()(Args&&... v) noexcept + void operator()(Args&&... v) const noexcept { std::array atoms; static constexpr int N = sizeof...(Args); diff --git a/include/avnd/binding/max/to_atoms.hpp b/include/avnd/binding/max/to_atoms.hpp index 4f6ecd46..fa610aac 100644 --- a/include/avnd/binding/max/to_atoms.hpp +++ b/include/avnd/binding/max/to_atoms.hpp @@ -1,12 +1,11 @@ #pragma once #include -#include #include #include - +#include #include - #include +#include namespace max { @@ -27,7 +26,15 @@ struct to_list { atom_setlong(&atoms.emplace_back(), arg); } - void operator()(std::string_view v) noexcept + + template + requires std::is_enum_v + void operator()(T arg) noexcept + { + atom_setsym(&atoms.emplace_back(), gensym(magic_enum::enum_name(arg).data())); + } + + void operator()(std::string_view v) noexcept { atom_setsym(&atoms.emplace_back(), gensym(v.data())); } @@ -47,9 +54,9 @@ struct to_list (*this)(0); } - template - requires std::is_aggregate_v - void operator()(const F& f) noexcept + template + requires(std::is_aggregate_v && !avnd::iterable_ish && !avnd::tuple_ish) + void operator()(const F& f) noexcept { atoms.reserve(atoms.size() + boost::pfr::tuple_size_v); @@ -59,25 +66,7 @@ struct to_list }); } - template - void operator()(const std::array& f) noexcept - { - atoms.reserve(atoms.size() + f.size()); - for(auto& v : f) { - (*this)(v); - } - } - - - void operator()(const avnd::set_ish auto& f) noexcept - { - atoms.reserve(atoms.size() + f.size()); - for(auto& v : f) { - (*this)(v); - } - } - - void operator()(const avnd::span_ish auto& f) noexcept + void operator()(const avnd::iterable_ish auto& f) noexcept { atoms.reserve(atoms.size() + f.size()); for(auto& v : f) { @@ -103,8 +92,9 @@ struct to_list (*this)(f.second); } - template - void operator()(const U& f) noexcept + template + requires(!avnd::iterable_ish) + void operator()(const U& f) noexcept { atoms.reserve(atoms.size() + std::tuple_size_v); std::apply( @@ -139,7 +129,14 @@ struct to_dict dictionary_appendstring(d, k, v.data()); } - void operator()(t_symbol* k, const avnd::variant_ish auto& f) noexcept + template + requires std::is_enum_v + void operator()(t_symbol* k, T&& arg) noexcept + { + dictionary_appendstring(d, k, magic_enum::enum_name(arg).data()); + } + + void operator()(t_symbol* k, const avnd::variant_ish auto& f) noexcept { visit([this, k](auto&& val) { (*this)(k, val); }, f); } @@ -204,7 +201,7 @@ struct to_dict { for(long i = 0; i < n; i++) { - if(!f->contains(keys[i]->s_name)) + if(!f.contains(keys[i]->s_name)) dictionary_deleteentry(d, keys[i]); } dictionary_freekeys(d, n, keys); @@ -243,6 +240,14 @@ struct set_atom atom_setsym(at, gensym(v.data())); return MAX_ERR_NONE; } + + template + requires std::is_enum_v + t_max_err operator()(t_atom* at, T arg) noexcept + { + atom_setsym(at, gensym(magic_enum::enum_name(arg).data())); + return MAX_ERR_NONE; + } }; struct to_atoms @@ -298,5 +303,49 @@ struct to_atoms } return MAX_ERR_OUT_OF_MEM; } + + template + requires std::is_enum_v + t_max_err operator()(T arg) noexcept + { + if(auto atoms = allocate(1, ac, av); !atoms.empty()) + { + atom_setsym(&atoms[0], gensym(magic_enum::enum_name(arg).data())); + return MAX_ERR_NONE; + } + return MAX_ERR_OUT_OF_MEM; + } + + template + t_max_err operator()(const T& arg) noexcept + { + if(auto atoms = allocate(std::size(arg), ac, av); !atoms.empty()) + { + using span_val_type = typename T::value_type; + int i = 0; + if constexpr(std::is_integral_v) + { + for(auto& v : arg) + atom_setlong(&atoms[i++], v); + } + else if constexpr(std::is_floating_point_v) + { + for(auto& v : arg) + atom_setfloat(&atoms[i], v); + } + else if constexpr(avnd::string_ish) + { + for(auto& v : arg) + atom_setsym(&atoms[i], gensym(v.data())); + } + else if constexpr(std::is_enum_v) + { + for(auto& v : arg) + atom_setsym(&atoms[i], gensym(magic_enum::enum_name(v).data())); + } + return MAX_ERR_NONE; + } + return MAX_ERR_OUT_OF_MEM; + } }; } diff --git a/include/avnd/binding/pd/construct.hpp b/include/avnd/binding/pd/construct.hpp index 5a34e918..84848d03 100644 --- a/include/avnd/binding/pd/construct.hpp +++ b/include/avnd/binding/pd/construct.hpp @@ -206,7 +206,7 @@ struct construct_arguments { return call_vec(implementation, name, argc, argv); } - else if constexpr(avnd::span_ish) + else if constexpr(avnd::iterable_ish) { return call_span(implementation, name, argc, argv); } diff --git a/include/avnd/binding/pd/helpers.hpp b/include/avnd/binding/pd/helpers.hpp index 1a7c8072..22fb8af8 100644 --- a/include/avnd/binding/pd/helpers.hpp +++ b/include/avnd/binding/pd/helpers.hpp @@ -23,18 +23,20 @@ concept convertible_to_fundamental_value_type template struct convertible_to_fundamental_value_type_pred : std::bool_constant>{}; +// clang-format off template concept convertible_to_atom_list_statically_impl = convertible_to_fundamental_value_type || (avnd::bitset_ish) || - (avnd::span_ish && convertible_to_fundamental_value_type) || + (avnd::iterable_ish && convertible_to_fundamental_value_type) || (avnd::pair_ish && convertible_to_fundamental_value_type && convertible_to_fundamental_value_type) || (avnd::map_ish && convertible_to_fundamental_value_type && convertible_to_fundamental_value_type) || (avnd::optional_ish && convertible_to_fundamental_value_type) || (avnd::variant_ish && boost::mp11::mp_all_of::value) || (avnd::tuple_ish && boost::mp11::mp_all_of::value) || - (std::is_aggregate_v && !avnd::span_ish && boost::mp11::mp_all_of, convertible_to_fundamental_value_type_pred>::value) + (std::is_aggregate_v && !avnd::iterable_ish && boost::mp11::mp_all_of, convertible_to_fundamental_value_type_pred>::value) ; +// clang-format on template concept convertible_to_atom_list_statically = convertible_to_atom_list_statically_impl>; @@ -162,7 +164,7 @@ t_symbol* symbol_for_port() return &s_list; else if constexpr(avnd::tuple_ish) return &s_list; - else if constexpr(avnd::span_ish) + else if constexpr(avnd::iterable_ish) return &s_list; else if constexpr(std::floating_point) return &s_float; diff --git a/include/avnd/binding/pd/init.hpp b/include/avnd/binding/pd/init.hpp index a442fd48..89d29e65 100644 --- a/include/avnd/binding/pd/init.hpp +++ b/include/avnd/binding/pd/init.hpp @@ -123,7 +123,7 @@ struct init_arguments call_vec(implementation, name, argc, argv); return; } - else if constexpr(avnd::span_ish) + else if constexpr(avnd::iterable_ish) { call_span(implementation, name, argc, argv); return; diff --git a/include/avnd/binding/pd/inputs.hpp b/include/avnd/binding/pd/inputs.hpp index 75773a46..4f2f2a98 100644 --- a/include/avnd/binding/pd/inputs.hpp +++ b/include/avnd/binding/pd/inputs.hpp @@ -22,7 +22,7 @@ struct from_atom requires std::is_aggregate_v bool operator()(T& v) const noexcept = delete; - bool operator()(avnd::span_ish auto& v) const noexcept = delete; + bool operator()(avnd::iterable_ish auto& v) const noexcept = delete; bool operator()(avnd::pair_ish auto& v) const noexcept = delete; bool operator()(avnd::tuple_ish auto& v) const noexcept = delete; bool operator()(avnd::map_ish auto& v) const noexcept = delete; @@ -147,6 +147,20 @@ struct from_atoms return true; } + template + bool operator()(T& v) const noexcept + { + v.clear(); + + for(int i = 0; i < ac; i++) + { + typename T::value_type item; + from_atom{av[i]}(item); + v.push_back(std::move(item)); + } + return true; + } + template bool operator()(avnd::array_ish auto& v) const noexcept { @@ -283,7 +297,9 @@ struct from_atoms } template - requires(std::is_aggregate_v && !avnd::span_ish && avnd::pfr::tuple_size_v > 0) + requires( + std::is_aggregate_v && !avnd::iterable_ish + && avnd::pfr::tuple_size_v > 0) bool operator()(T& v) const noexcept { avnd::for_each_field_ref(v, [this, i = 0] (F& field) mutable { diff --git a/include/avnd/binding/pd/outputs.hpp b/include/avnd/binding/pd/outputs.hpp index c9a399cd..cb422c56 100644 --- a/include/avnd/binding/pd/outputs.hpp +++ b/include/avnd/binding/pd/outputs.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -23,6 +24,13 @@ inline void value_to_pd(t_atom& atom, bool v) noexcept { atom = {.a_type = A_FLOAT, .a_w = {.w_float = v ? 1.0f : 0.0f}}; } +template + requires std::is_enum_v +inline void value_to_pd(t_atom& atom, T v) noexcept +{ + atom = { + .a_type = A_SYMBOL, .a_w = {.w_symbol = gensym(magic_enum::enum_name(v).data())}}; +} inline void value_to_pd(t_atom& atom, const char* v) noexcept { atom = {.a_type = A_SYMBOL, .a_w = {.w_symbol = gensym(v)}}; @@ -50,7 +58,7 @@ struct do_value_to_pd_rec boost::container::small_vector atoms; template - requires(std::is_aggregate_v && !avnd::span_ish && !avnd::tuple_ish) + requires(std::is_aggregate_v && !avnd::iterable_ish && !avnd::tuple_ish) void operator()(const T& v) { static constexpr int sz = avnd::pfr::tuple_size_v; @@ -80,6 +88,14 @@ struct do_value_to_pd_rec { atoms.push_back({.a_type = A_FLOAT, .a_w = {.w_float = (t_float)v}}); } + template + requires std::is_enum_v + void operator()(T v) noexcept + { + atoms.push_back( + {.a_type = A_SYMBOL, + .a_w = {.w_symbol = gensym(magic_enum::enum_name(v).data())}}); + } void operator()(std::string_view v) noexcept { atoms.push_back({.a_type = A_SYMBOL, .a_w = {.w_symbol = gensym(v.data())}}); @@ -114,6 +130,15 @@ struct do_value_to_pd_rec visit([this](const auto& val) { (*this)(val); }, v); } + void operator()(const avnd::optional_ish auto& v) noexcept + { + using namespace std; + if(v) + (*this)(*v); + else + atoms.push_back({.a_type = A_NULL, .a_w = {.w_float = 0}}); + } + void operator()(const avnd::pair_ish auto& v) noexcept { (*this)(v.first); @@ -134,14 +159,11 @@ struct do_value_to_pd_rec struct do_value_to_pd_typed { - void operator()(t_outlet* outlet) - { - outlet_bang(outlet); - } + void operator()(t_outlet* outlet) const noexcept { outlet_bang(outlet); } template - requires (std::is_aggregate_v && !avnd::span_ish && !avnd::tuple_ish) - void operator()(t_outlet* outlet, const T& v) + requires(std::is_aggregate_v && !avnd::iterable_ish && !avnd::tuple_ish) + void operator()(t_outlet* outlet, const T& v) const noexcept { static constexpr int sz = avnd::pfr::tuple_size_v; @@ -161,9 +183,22 @@ struct do_value_to_pd_typed } } + template + void operator()(t_outlet* outlet, const T& v) const noexcept + { + static constexpr int N = std::tuple_size_v; + std::array atoms; + + [&](std::index_sequence) { + (value_to_pd(atoms[I], std::get(v)), ...); + }(std::make_index_sequence{}); + + outlet_list(outlet, &s_list, N, atoms.data()); + } + template requires avnd::span_ish - void operator()(t_outlet* outlet, const T& v) + void operator()(t_outlet* outlet, const T& v) const noexcept { static_assert(convertible_to_fundamental_value_type); // FIXME does not work for recursivity: static thread_local. We need a pool. @@ -181,7 +216,7 @@ struct do_value_to_pd_typed } template - void operator()(t_outlet* outlet, const std::array& v) + void operator()(t_outlet* outlet, const std::array& v) const noexcept { static_assert(convertible_to_fundamental_value_type); std::array atoms; @@ -195,7 +230,7 @@ struct do_value_to_pd_typed } template - void operator()(t_outlet* outlet, const avnd::array_ish auto& v) + void operator()(t_outlet* outlet, const avnd::array_ish auto& v) const noexcept { std::array atoms; @@ -208,8 +243,8 @@ struct do_value_to_pd_typed } template - requires avnd::set_ish - void operator()(t_outlet* outlet, const T& v) + requires((avnd::set_ish || avnd::list_ish) && !avnd::vector_ish) + void operator()(t_outlet* outlet, const T& v) const noexcept { static thread_local std::vector atoms; const int N = v.size(); @@ -226,7 +261,7 @@ struct do_value_to_pd_typed template requires avnd::map_ish - void operator()(t_outlet* outlet, const T& v) + void operator()(t_outlet* outlet, const T& v) const noexcept { static thread_local std::vector atoms; const int N = v.size(); @@ -244,15 +279,15 @@ struct do_value_to_pd_typed template requires avnd::variant_ish - void operator()(t_outlet* outlet, const T& v) + void operator()(t_outlet* outlet, const T& v) const noexcept { using namespace std; - visit(v, [&](const auto& element) { (*this)(outlet, element); }); + visit([&](const auto& element) { (*this)(outlet, element); }, v); } template requires avnd::pair_ish - void operator()(t_outlet* outlet, const T& v) + void operator()(t_outlet* outlet, const T& v) const noexcept { t_atom atoms[2]; @@ -264,40 +299,53 @@ struct do_value_to_pd_typed template requires avnd::optional_ish - void operator()(t_outlet* outlet, const T& v) + void operator()(t_outlet* outlet, const T& v) const noexcept { if(v) (*this)(outlet, *v); } - inline void operator()(t_outlet* outlet, std::integral auto v) noexcept + inline void operator()(t_outlet* outlet, std::integral auto v) const noexcept { outlet_float(outlet, v); } - inline void operator()(t_outlet* outlet, std::floating_point auto v) noexcept + inline void operator()(t_outlet* outlet, std::floating_point auto v) const noexcept { outlet_float(outlet, v); } - inline void operator()(t_outlet* outlet, bool v) noexcept + inline void operator()(t_outlet* outlet, bool v) const noexcept { outlet_float(outlet, v ? 1.f : 0.f); } - inline void operator()(t_outlet* outlet, const char* v) noexcept + inline void operator()(t_outlet* outlet, const char* v) const noexcept { outlet_symbol(outlet, gensym(v)); } - inline void operator()(t_outlet* outlet, std::string_view v) noexcept + inline void operator()(t_outlet* outlet, std::string_view v) const noexcept { outlet_symbol(outlet, gensym(v.data())); } - inline void operator()(t_outlet* outlet, const std::string& v) noexcept + inline void operator()(t_outlet* outlet, const std::string& v) const noexcept { outlet_symbol(outlet, gensym(v.c_str())); } + void operator()(t_outlet* outlet, const avnd::bitset_ish auto& v) const noexcept + { + boost::container::small_vector atoms; + const int N = v.size(); + atoms.resize(2 * N); + + for(int i = 0, N = v.size(); i < N; i++) + { + value_to_pd(atoms[i], v.test(i) ? 1 : 0); + } + + outlet_list(outlet, &s_list, N, atoms.data()); + } template requires(sizeof...(Args) > 1) - inline void operator()(t_outlet* outlet, Args&&... v) noexcept + inline void operator()(t_outlet* outlet, Args&&... v) const noexcept { std::array atoms; static constexpr int N = sizeof...(Args); @@ -312,14 +360,14 @@ struct do_value_to_pd_typed struct do_value_to_pd_anything { - void operator()(t_outlet* outlet, t_symbol* sym) + void operator()(t_outlet* outlet, t_symbol* sym) const noexcept { outlet_anything(outlet, sym, 0, nullptr); } template - requires(std::is_aggregate_v && !avnd::span_ish && !avnd::tuple_ish) - void operator()(t_outlet* outlet, t_symbol* sym, const T& v) + requires(std::is_aggregate_v && !avnd::iterable_ish && !avnd::tuple_ish) + void operator()(t_outlet* outlet, t_symbol* sym, const T& v) const noexcept { static constexpr int sz = avnd::pfr::tuple_size_v; @@ -343,7 +391,7 @@ struct do_value_to_pd_anything template requires avnd::span_ish - void operator()(t_outlet* outlet, t_symbol* sym, const T& v) + void operator()(t_outlet* outlet, t_symbol* sym, const T& v) const noexcept { static thread_local std::vector atoms; const int N = v.size(); @@ -360,7 +408,8 @@ struct do_value_to_pd_anything // FIXME msvc isn't able to match the more generic template template - void operator()(t_outlet* outlet, t_symbol* sym, const std::array& v) + void + operator()(t_outlet* outlet, t_symbol* sym, const std::array& v) const noexcept { std::array atoms; @@ -373,7 +422,8 @@ struct do_value_to_pd_anything } template - void operator()(t_outlet* outlet, t_symbol* sym, const avnd::array_ish auto& v) + void operator()( + t_outlet* outlet, t_symbol* sym, const avnd::array_ish auto& v) const noexcept { std::array atoms; @@ -386,8 +436,8 @@ struct do_value_to_pd_anything } template - requires avnd::set_ish - void operator()(t_outlet* outlet, t_symbol* sym, const T& v) + requires((avnd::set_ish || avnd::list_ish) && !avnd::vector_ish) + void operator()(t_outlet* outlet, t_symbol* sym, const T& v) const noexcept { // FIXME that does not work, we can have recursive types static thread_local std::vector atoms; @@ -405,7 +455,7 @@ struct do_value_to_pd_anything template requires avnd::map_ish - void operator()(t_outlet* outlet, t_symbol* sym, const T& v) + void operator()(t_outlet* outlet, t_symbol* sym, const T& v) const noexcept { static thread_local std::vector atoms; const int N = v.size(); @@ -423,15 +473,15 @@ struct do_value_to_pd_anything template requires avnd::variant_ish - void operator()(t_outlet* outlet, t_symbol* sym, const T& v) + void operator()(t_outlet* outlet, t_symbol* sym, const T& v) const noexcept { using namespace std; - visit(v, [&](const auto& element) { (*this)(outlet, sym, element); }); + visit([&](const auto& element) { (*this)(outlet, sym, element); }, v); } template requires avnd::pair_ish - void operator()(t_outlet* outlet, t_symbol* sym, const T& v) + void operator()(t_outlet* outlet, t_symbol* sym, const T& v) const noexcept { t_atom atoms[2]; @@ -443,13 +493,14 @@ struct do_value_to_pd_anything template requires avnd::optional_ish - void operator()(t_outlet* outlet, t_symbol* sym, const T& v) + void operator()(t_outlet* outlet, t_symbol* sym, const T& v) const noexcept { if(v) (*this)(outlet, sym, *v); } - inline void operator()(t_outlet* outlet, t_symbol* sym, std::integral auto v) noexcept + inline void + operator()(t_outlet* outlet, t_symbol* sym, std::integral auto v) const noexcept { t_atom atom; value_to_pd(atom, v); @@ -457,44 +508,74 @@ struct do_value_to_pd_anything } inline void - operator()(t_outlet* outlet, t_symbol* sym, std::floating_point auto v) noexcept + operator()(t_outlet* outlet, t_symbol* sym, std::floating_point auto v) const noexcept { t_atom atom; value_to_pd(atom, v); outlet_anything(outlet, sym, 1, &atom); } - inline void operator()(t_outlet* outlet, t_symbol* sym, bool v) noexcept + inline void operator()(t_outlet* outlet, t_symbol* sym, bool v) const noexcept { t_atom atom; value_to_pd(atom, v); outlet_anything(outlet, sym, 1, &atom); } - inline void operator()(t_outlet* outlet, t_symbol* sym, const char* v) noexcept + inline void operator()(t_outlet* outlet, t_symbol* sym, const char* v) const noexcept { t_atom atom; value_to_pd(atom, v); outlet_anything(outlet, sym, 1, &atom); } - inline void operator()(t_outlet* outlet, t_symbol* sym, std::string_view v) noexcept + inline void + operator()(t_outlet* outlet, t_symbol* sym, std::string_view v) const noexcept { t_atom atom; value_to_pd(atom, v); outlet_anything(outlet, sym, 1, &atom); } - inline void operator()(t_outlet* outlet, t_symbol* sym, const std::string& v) noexcept + inline void + operator()(t_outlet* outlet, t_symbol* sym, const std::string& v) const noexcept { t_atom atom; value_to_pd(atom, v); outlet_anything(outlet, sym, 1, &atom); } + void operator()( + t_outlet* outlet, t_symbol* sym, const avnd::bitset_ish auto& v) const noexcept + { + boost::container::small_vector atoms; + const int N = v.size(); + atoms.resize(2 * N); + + for(int i = 0, N = v.size(); i < N; i++) + { + value_to_pd(atoms[i], v.test(i) ? 1 : 0); + } + + outlet_anything(outlet, sym, N, atoms.data()); + } + + template + void operator()(t_outlet* outlet, t_symbol* sym, const T& v) const noexcept + { + static constexpr int N = std::tuple_size_v; + std::array atoms; + + [&](std::index_sequence) { + (value_to_pd(atoms[I], std::get(v)), ...); + }(std::make_index_sequence{}); + + outlet_anything(outlet, sym, N, atoms.data()); + } + template requires(sizeof...(Args) > 1) - inline void operator()(t_outlet* outlet, t_symbol* sym, Args&&... v) noexcept + inline void operator()(t_outlet* outlet, t_symbol* sym, Args&&... v) const noexcept { std::array atoms; static constexpr int N = sizeof...(Args); diff --git a/include/avnd/concepts/generic.hpp b/include/avnd/concepts/generic.hpp index ee35abd4..21613c9b 100644 --- a/include/avnd/concepts/generic.hpp +++ b/include/avnd/concepts/generic.hpp @@ -51,13 +51,15 @@ concept iterable_ish = requires(const T& t) { template concept span_ish = iterable_ish && requires(const T& t) { t[0]; }; template -concept vector_ish = span_ish && requires(T t) { +concept list_ish = requires(T t) { t.push_back({}); // t.reserve(1); // many containers don't have it t.resize(1); t.clear(); // t.data(); // did you know? std::vector does not have it }; +template +concept vector_ish = span_ish && list_ish; template concept set_ish = iterable_ish && requires(T t) { @@ -95,18 +97,6 @@ concept vector_v_ish = span_ish && requires(T t) { template concept vector_v_strict = vector_ish && std::is_same_v; -template -concept variant_ish = requires(T t) { - t.index(); - t.valueless_by_exception(); - }; - -template -concept pair_ish = requires(T t) { - t.first; - t.second; - } && (std::tuple_size_v == 2); - template concept tuple_ish = requires(const T& t) { std::tuple_size::value; @@ -114,6 +104,18 @@ concept tuple_ish = requires(const T& t) { std::get<0>(t); }; +template +concept variant_ish = requires(T t) { + t.index(); + t.valueless_by_exception(); +}; + +template +concept pair_ish = tuple_ish && requires(T t) { + t.first; + t.second; +} && (std::tuple_size_v == 2); + template concept optional_ish = requires(T t) { bool(t);