diff options
Diffstat (limited to 'libcxx/include/__format/format_context.h')
| -rw-r--r-- | libcxx/include/__format/format_context.h | 88 |
1 files changed, 80 insertions, 8 deletions
diff --git a/libcxx/include/__format/format_context.h b/libcxx/include/__format/format_context.h index b9a41db05d51..85e00eb222cf 100644 --- a/libcxx/include/__format/format_context.h +++ b/libcxx/include/__format/format_context.h @@ -11,14 +11,19 @@ #define _LIBCPP___FORMAT_FORMAT_CONTEXT_H #include <__availability> +#include <__concepts/same_as.h> #include <__config> #include <__format/buffer.h> +#include <__format/format_arg.h> +#include <__format/format_arg_store.h> #include <__format/format_args.h> +#include <__format/format_error.h> #include <__format/format_fwd.h> #include <__iterator/back_insert_iterator.h> #include <__iterator/concepts.h> +#include <__memory/addressof.h> #include <__utility/move.h> -#include <concepts> +#include <__variant/monostate.h> #include <cstddef> #ifndef _LIBCPP_HAS_NO_LOCALIZATION @@ -50,8 +55,7 @@ __format_context_create( _OutIt __out_it, basic_format_args<basic_format_context<_OutIt, _CharT>> __args, optional<_VSTD::locale>&& __loc = nullopt) { - return _VSTD::basic_format_context(_VSTD::move(__out_it), __args, - _VSTD::move(__loc)); + return _VSTD::basic_format_context(_VSTD::move(__out_it), __args, _VSTD::move(__loc)); } #else template <class _OutIt, class _CharT> @@ -87,9 +91,6 @@ public: template <class _Tp> using formatter_type = formatter<_Tp, _CharT>; - basic_format_context(const basic_format_context&) = delete; - basic_format_context& operator=(const basic_format_context&) = delete; - _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept { return __args_.get(__id); @@ -101,8 +102,8 @@ public: return *__loc_; } #endif - _LIBCPP_HIDE_FROM_ABI iterator out() { return __out_it_; } - _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = __it; } + _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); } + _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); } private: iterator __out_it_; @@ -144,6 +145,77 @@ private: #endif }; +// A specialization for __retarget_buffer +// +// See __retarget_buffer for the motivation for this specialization. +// +// This context holds a reference to the instance of the basic_format_context +// that is retargeted. It converts a formatting argument when it is requested +// during formatting. It is expected that the usage of the arguments is rare so +// the lookups are not expected to be used often. An alternative would be to +// convert all elements during construction. +// +// The elements of the retargets context are only used when an underlying +// formatter uses a locale specific formatting or an formatting argument is +// part for the format spec. For example +// format("{:256:{}}", input, 8); +// Here the width of an element in input is determined dynamically. +// Note when the top-level element has no width the retargeting is not needed. +template <class _CharT> +class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT + basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> { +public: + using iterator = typename __format::__retarget_buffer<_CharT>::__iterator; + using char_type = _CharT; + template <class _Tp> + using formatter_type = formatter<_Tp, _CharT>; + + template <class _Context> + _LIBCPP_HIDE_FROM_ABI explicit basic_format_context(iterator __out_it, _Context& __ctx) + : __out_it_(std::move(__out_it)), +# ifndef _LIBCPP_HAS_NO_LOCALIZATION + __loc_([](void* __c) { return static_cast<_Context*>(__c)->locale(); }), +# 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)); + }) { + } + + _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept { + return __arg_(__ctx_, __id); + } +# ifndef _LIBCPP_HAS_NO_LOCALIZATION + _LIBCPP_HIDE_FROM_ABI _VSTD::locale locale() { return __loc_(__ctx_); } +# endif + _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); } + _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); } + +private: + iterator __out_it_; + +# ifndef _LIBCPP_HAS_NO_LOCALIZATION + std::locale (*__loc_)(void* __ctx); +# endif + + void* __ctx_; + basic_format_arg<basic_format_context> (*__arg_)(void* __ctx, size_t __id); +}; + +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_context); #endif //_LIBCPP_STD_VER > 17 _LIBCPP_END_NAMESPACE_STD |
