Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reland: [libc++][format] P2637R3: Member visit (std::basic_format_arg) #76449 #79032

Merged
merged 13 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libcxx/docs/ReleaseNotes/19.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ see the `releases page <https://llvm.org/releases/>`_.
What's New in Libc++ 19.0.0?
==============================

TODO
- P2637R3 - Member ``visit``


Implemented Papers
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2cPapers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"`P0792R14 <https://wg21.link/P0792R14>`__","LWG","``function_ref``: a type-erased callable reference","Varna June 2023","","",""
"`P2874R2 <https://wg21.link/P2874R2>`__","LWG","Mandating Annex D Require No More","Varna June 2023","","",""
"`P2757R3 <https://wg21.link/P2757R3>`__","LWG","Type-checking format args","Varna June 2023","","","|format|"
"`P2637R3 <https://wg21.link/P2637R3>`__","LWG","Member ``visit``","Varna June 2023","|Partial|","18.0",""
"`P2637R3 <https://wg21.link/P2637R3>`__","LWG","Member ``visit``","Varna June 2023","|Complete|","19.0",""
"`P2641R4 <https://wg21.link/P2641R4>`__","CWG, LWG","Checking if a ``union`` alternative is active","Varna June 2023","","",""
"`P1759R6 <https://wg21.link/P1759R6>`__","LWG","Native handles and file streams","Varna June 2023","|Complete|","18.0",""
"`P2697R1 <https://wg21.link/P2697R1>`__","LWG","Interfacing ``bitset`` with ``string_view``","Varna June 2023","|Complete|","18.0",""
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/FormatIssues.csv
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Number,Name,Standard,Assignee,Status,First released version
"`P2693R1 <https://wg21.link/P2693R1>`__","Formatting ``thread::id`` and ``stacktrace``","C++23","Mark de Wever","|In Progress|"
"`P2510R3 <https://wg21.link/P2510R3>`__","Formatting pointers","C++26","Mark de Wever","|Complete|",17.0
"`P2757R3 <https://wg21.link/P2757R3>`__","Type-checking format args","C++26","","",
"`P2637R3 <https://wg21.link/P2637R3>`__","Member ``visit``","C++26","","",
"`P2637R3 <https://wg21.link/P2637R3>`__","Member ``visit``","C++26","Hristo Hristov","|Complete|",19.0
"`P2905R2 <https://wg21.link/P2905R2>`__","Runtime format strings","C++26 DR","Mark de Wever","|Complete|",18.0
"`P2918R2 <https://wg21.link/P2918R2>`__","Runtime format strings II","C++26","Mark de Wever","|Complete|",18.0
"`P2909R4 <https://wg21.link/P2909R4>`__","Fix formatting of code units as integers (Dude, where’s my ``char``?)","C++26 DR","Mark de Wever","|Complete|",18.0
Expand Down
6 changes: 6 additions & 0 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,12 @@ typedef __char32_t char32_t;
# define _LIBCPP_DEPRECATED_IN_CXX23
# endif

# if _LIBCPP_STD_VER >= 26
# define _LIBCPP_DEPRECATED_IN_CXX26 _LIBCPP_DEPRECATED
# else
# define _LIBCPP_DEPRECATED_IN_CXX26
# endif

# if !defined(_LIBCPP_HAS_NO_CHAR8_T)
# define _LIBCPP_DEPRECATED_WITH_CHAR8_T _LIBCPP_DEPRECATED
# else
Expand Down
109 changes: 106 additions & 3 deletions libcxx/include/__format/format_arg.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr __arg_t __get_packed_type(uint64_t __types, size

} // namespace __format

// This function is not user obervable, so it can directly use the non-standard
// This function is not user observable, so it can directly use the non-standard
// types of the "variant". See __arg_t for more details.
template <class _Visitor, class _Context>
_LIBCPP_HIDE_FROM_ABI decltype(auto) __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
Expand Down Expand Up @@ -147,6 +147,59 @@ _LIBCPP_HIDE_FROM_ABI decltype(auto) __visit_format_arg(_Visitor&& __vis, basic_
__libcpp_unreachable();
}

# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)

template <class _Rp, class _Visitor, class _Context>
_LIBCPP_HIDE_FROM_ABI _Rp __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
switch (__arg.__type_) {
case __format::__arg_t::__none:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__monostate_);
case __format::__arg_t::__boolean:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__boolean_);
case __format::__arg_t::__char_type:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__char_type_);
case __format::__arg_t::__int:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__int_);
case __format::__arg_t::__long_long:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__long_long_);
case __format::__arg_t::__i128:
# ifndef _LIBCPP_HAS_NO_INT128
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__i128_);
# else
__libcpp_unreachable();
# endif
case __format::__arg_t::__unsigned:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_);
case __format::__arg_t::__unsigned_long_long:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_long_long_);
case __format::__arg_t::__u128:
# ifndef _LIBCPP_HAS_NO_INT128
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__u128_);
# else
__libcpp_unreachable();
# endif
case __format::__arg_t::__float:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__float_);
case __format::__arg_t::__double:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__double_);
case __format::__arg_t::__long_double:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__long_double_);
case __format::__arg_t::__const_char_type_ptr:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__const_char_type_ptr_);
case __format::__arg_t::__string_view:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__string_view_);
case __format::__arg_t::__ptr:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__ptr_);
case __format::__arg_t::__handle:
return std::invoke_r<_Rp>(
std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__arg.__value_.__handle_});
}

__libcpp_unreachable();
}

# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)

/// Contains the values used in basic_format_arg.
///
/// This is a separate type so it's possible to store the values and types in
Expand Down Expand Up @@ -230,6 +283,52 @@ class _LIBCPP_TEMPLATE_VIS basic_format_arg {

_LIBCPP_HIDE_FROM_ABI explicit operator bool() const noexcept { return __type_ != __format::__arg_t::__none; }

# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)

// This function is user facing, so it must wrap the non-standard types of
// the "variant" in a handle to stay conforming. See __arg_t for more details.
template <class _Visitor>
_LIBCPP_HIDE_FROM_ABI decltype(auto) visit(this basic_format_arg __arg, _Visitor&& __vis) {
switch (__arg.__type_) {
# ifndef _LIBCPP_HAS_NO_INT128
case __format::__arg_t::__i128: {
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__i128_};
return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}

case __format::__arg_t::__u128: {
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_};
return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}
# endif
default:
return std::__visit_format_arg(std::forward<_Visitor>(__vis), __arg);
}
}

// This function is user facing, so it must wrap the non-standard types of
// the "variant" in a handle to stay conforming. See __arg_t for more details.
template <class _Rp, class _Visitor>
_LIBCPP_HIDE_FROM_ABI _Rp visit(this basic_format_arg __arg, _Visitor&& __vis) {
switch (__arg.__type_) {
# ifndef _LIBCPP_HAS_NO_INT128
case __format::__arg_t::__i128: {
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__i128_};
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}

case __format::__arg_t::__u128: {
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_};
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}
# endif
default:
return std::__visit_format_arg<_Rp>(std::forward<_Visitor>(__vis), __arg);
}
}

# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)

private:
using char_type = typename _Context::char_type;

Expand Down Expand Up @@ -270,7 +369,11 @@ class _LIBCPP_TEMPLATE_VIS basic_format_arg<_Context>::handle {
// This function is user facing, so it must wrap the non-standard types of
// the "variant" in a handle to stay conforming. See __arg_t for more details.
template <class _Visitor, class _Context>
_LIBCPP_HIDE_FROM_ABI decltype(auto) visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
_LIBCPP_DEPRECATED_IN_CXX26
# endif
_LIBCPP_HIDE_FROM_ABI decltype(auto)
visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
switch (__arg.__type_) {
# ifndef _LIBCPP_HAS_NO_INT128
case __format::__arg_t::__i128: {
Expand All @@ -282,7 +385,7 @@ _LIBCPP_HIDE_FROM_ABI decltype(auto) visit_format_arg(_Visitor&& __vis, basic_fo
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_};
return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}
# endif
# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
default:
return std::__visit_format_arg(std::forward<_Visitor>(__vis), __arg);
}
Expand Down
33 changes: 19 additions & 14 deletions libcxx/include/__format/format_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,20 +166,25 @@ class _LIBCPP_TEMPLATE_VIS basic_format_context<typename __format::__retarget_bu
# endif
__ctx_(std::addressof(__ctx)),
__arg_([](void* __c, size_t __id) {
return std::visit_format_arg(
[&](auto __arg) -> basic_format_arg<basic_format_context> {
if constexpr (same_as<decltype(__arg), monostate>)
return {};
else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Context>::handle>)
// At the moment it's not possible for formatting to use a re-targeted handle.
// TODO FMT add this when support is needed.
std::__throw_format_error("Re-targeting handle not supported");
else
return basic_format_arg<basic_format_context>{
__format::__determine_arg_t<basic_format_context, decltype(__arg)>(),
__basic_format_arg_value<basic_format_context>(__arg)};
},
static_cast<_Context*>(__c)->arg(__id));
auto __visitor = [&](auto __arg) -> basic_format_arg<basic_format_context> {
if constexpr (same_as<decltype(__arg), monostate>)
return {};
else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Context>::handle>)
// At the moment it's not possible for formatting to use a re-targeted handle.
// TODO FMT add this when support is needed.
std::__throw_format_error("Re-targeting handle not supported");
else
return basic_format_arg<basic_format_context>{
__format::__determine_arg_t<basic_format_context, decltype(__arg)>(),
__basic_format_arg_value<basic_format_context>(__arg)};
};
# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
return static_cast<_Context*>(__c)->arg(__id).visit(std::move(__visitor));
# else
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
return std::visit_format_arg(std::move(__visitor), static_cast<_Context*>(__c)->arg(__id));
_LIBCPP_SUPPRESS_DEPRECATED_POP
# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
}) {
}

Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/format
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ namespace std {
template<class Context> class basic_format_arg;

template<class Visitor, class Context>
see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg); // Deprecated in C++26

// [format.arg.store], class template format-arg-store
template<class Context, class... Args> struct format-arg-store; // exposition only
Expand Down
Loading
Loading