glaze icon indicating copy to clipboard operation
glaze copied to clipboard

Glaze does not detect variant objects within variants

Open shiretu opened this issue 1 year ago • 2 comments

Hi,

Consider the following code snippet from the library, at which I have added some debugging:

using object_types = typename variant_types<T>::object_types;
std::cerr << "T: " << get_type_string<T>() << "\n";
std::cerr << "object_types: " << get_type_string<object_types>() << "\n";
std::cerr << "glz::tuple_size_v<object_types>: " << glz::tuple_size_v<object_types> << "\n";

the output looks like this:

T: std::variant<connected, std::variant<subscribed_v4_orderbook, subscribed_v4_subaccounts, subscribed_v4_trades>, std::variant<channel_data_v4_orderbook, channel_data_v4_trades>>
object_types: glz::tuplet::tuple<connected>
glz::tuple_size_v<object_types>: 1

That is not correct. Our input T type is a std::variant consisting of 3 types. last 2 types from this variant are themselves variants. The wanted output should have been:

object_types: glz::tuplet::tuple<connected, std::variant<subscribed_v4_orderbook, subscribed_v4_subaccounts, subscribed_v4_trades>, std::variant<channel_data_v4_orderbook, channel_data_v4_trades>>
glz::tuple_size_v<object_types>: 3

shiretu avatar Jun 13 '24 19:06 shiretu

Created this PR https://github.com/stephenberry/glaze/pull/1098 which also includes fixes for issue https://github.com/stephenberry/glaze/issues/1092

shiretu avatar Jun 13 '24 21:06 shiretu

This issue is due to the fact that a std::variant isn't necessarily an object. In this example the variant types all contain object types, so they should be considered objects. However, this recursive compile time type analysis is not simple, especially when trying to filter types.

I think the filtering code needs to be improved and optimized before this feature is added. I've pasted the current filtering code below. I'm removing the bug label because this is technically a limitation and not broken code.

I did improve the std::variant handling logic recently and added support for std::shared_ptr and std::unique_ptr in variants, but this effort is not a primary focus right now.

template <class>
struct variant_types;

template <class... Ts>
struct variant_types<std::variant<Ts...>>
{
   // TODO: this way of filtering types is compile time intensive.
   using bool_types = decltype(tuplet::tuple_cat(
      std::conditional_t<bool_t<remove_meta_wrapper_t<Ts>>, tuplet::tuple<Ts>, tuplet::tuple<>>{}...));
   using number_types = decltype(tuplet::tuple_cat(
      std::conditional_t<num_t<remove_meta_wrapper_t<Ts>>, tuplet::tuple<Ts>, tuplet::tuple<>>{}...));
   using string_types = decltype(tuplet::tuple_cat( // glaze_enum_t remove_meta_wrapper_t supports constexpr
                                                    // types while the other supports non const
      std::conditional_t < str_t<remove_meta_wrapper_t<Ts>> || glaze_enum_t<remove_meta_wrapper_t<Ts>> ||
         glaze_enum_t<Ts>,
      tuplet::tuple<Ts>, tuplet::tuple < >> {}...));
   using object_types =
      decltype(tuplet::tuple_cat(std::conditional_t<json_object<Ts>, tuplet::tuple<Ts>, tuplet::tuple<>>{}...));
   using array_types =
      decltype(tuplet::tuple_cat(std::conditional_t < array_t<remove_meta_wrapper_t<Ts>> || glaze_array_t<Ts>,
                                 tuplet::tuple<Ts>, tuplet::tuple < >> {}...));
   using nullable_types =
      decltype(tuplet::tuple_cat(std::conditional_t<null_t<Ts>, tuplet::tuple<Ts>, tuplet::tuple<>>{}...));
   using nullable_objects = decltype(tuplet::tuple_cat(
      std::conditional_t<is_memory_object<Ts>, tuplet::tuple<Ts>, tuplet::tuple<>>{}...));
};

stephenberry avatar Aug 08 '24 10:08 stephenberry