constexpr decltype()

in include/ylt/struct_pack/type_calculate.hpp [195:306]


constexpr decltype(auto) get_type_literal() {
  if constexpr (is_trivial_view_v<Arg>) {
    return get_type_literal<typename Arg::value_type, ParentArgs...>();
  }
  else if constexpr (user_defined_serialization<Arg>) {
    constexpr auto begin = string_literal<char, 1>{
        {static_cast<char>(type_id::user_defined_type)}};
    constexpr auto end =
        string_literal<char, 1>{{static_cast<char>(type_id::type_end_flag)}};
    if constexpr (user_defined_type_name<Arg>) {
      constexpr auto type_name = sp_set_type_name((Arg *)nullptr);
      string_literal<char, type_name.size()> ret{type_name};
      return begin + ret + end;
    }
    else {
      constexpr auto type_name = type_string<Arg>();
      string_literal<char, type_name.size()> ret{type_name};
      return begin + ret + end;
    }
  }
  else {
    constexpr std::size_t has_cycle = check_circle<Arg, ParentArgs...>();
    if constexpr (has_cycle != 0) {
      static_assert(has_cycle >= 2);
      return string_literal<char, 1>{
                 {static_cast<char>(type_id::circle_flag)}} +
             get_size_literal<has_cycle - 2>();
    }
    else {
      constexpr auto parent_tag = get_parent_tag<ParentArgs...>();
      constexpr auto id = get_type_id<Arg, parent_tag>();
      constexpr auto begin = string_literal<char, 1>{{static_cast<char>(id)}};
      if constexpr (id == type_id::struct_t) {
        using Args = decltype(get_types<Arg>());
        constexpr auto end = get_type_end_flag<Arg>();
        constexpr auto body = get_type_literal<Args, Arg, ParentArgs...>(
            std::make_index_sequence<std::tuple_size_v<Args>>());
        if constexpr (is_trivial_serializable<Arg, true>::value) {
          static_assert(
              align::pack_alignment_v<Arg> <= align::alignment_v<Arg>,
              "If you add #pragma_pack to a struct, please specify the "
              "struct_pack::pack_alignment_v<T>.");
          return begin + body +
                 get_size_literal<align::pack_alignment_v<Arg>>() +
                 get_size_literal<align::alignment_v<Arg>>() + end;
        }
        else {
          return begin + body + end;
        }
      }
      else if constexpr (id == type_id::variant_t) {
        constexpr auto sz = std::variant_size_v<Arg>;
        static_assert(sz > 0, "empty param of std::variant is not allowed!");
        static_assert(sz < 256, "too many alternative type in variant!");
        constexpr auto body = get_variant_literal<Arg, ParentArgs...>(
            std::make_index_sequence<std::variant_size_v<Arg>>());
        constexpr auto end = string_literal<char, 1>{
            {static_cast<char>(type_id::type_end_flag)}};
        return begin + body + end;
      }
      else if constexpr (id == type_id::array_t) {
        constexpr auto sz = get_array_size<Arg>();
        static_assert(sz > 0, "The array's size must greater than zero!");
        return begin +
               get_type_literal<
                   remove_cvref_t<decltype(std::declval<Arg>()[0])>, Arg,
                   ParentArgs...>() +
               get_size_literal<sz>();
      }
      else if constexpr (id == type_id::bitset_t) {
        constexpr auto sz = get_array_size<Arg>();
        static_assert(sz > 0, "The array's size must greater than zero!");
        return begin + get_size_literal<sz>();
      }
      else if constexpr (unique_ptr<Arg>) {
        return begin +
               get_type_literal<remove_cvref_t<typename Arg::element_type>, Arg,
                                ParentArgs...>();
      }
      else if constexpr (id == type_id::container_t ||
                         id == type_id::optional_t || id == type_id::string_t) {
        return begin +
               get_type_literal<remove_cvref_t<typename Arg::value_type>, Arg,
                                ParentArgs...>();
      }
      else if constexpr (id == type_id::set_container_t) {
        return begin + get_type_literal<remove_cvref_t<typename Arg::key_type>,
                                        Arg, ParentArgs...>();
      }
      else if constexpr (id == type_id::map_container_t) {
        return begin +
               get_type_literal<remove_cvref_t<typename Arg::key_type>, Arg,
                                ParentArgs...>() +
               get_type_literal<remove_cvref_t<typename Arg::mapped_type>, Arg,
                                ParentArgs...>();
      }
      else if constexpr (id == type_id::expected_t) {
        return begin +
               get_type_literal<remove_cvref_t<typename Arg::value_type>, Arg,
                                ParentArgs...>() +
               get_type_literal<remove_cvref_t<typename Arg::error_type>, Arg,
                                ParentArgs...>();
      }
      else if constexpr (id != type_id::compatible_t) {
        return begin;
      }
      else {
        return string_literal<char, 0>{};
      }
    }
  }
}