aboutsummaryrefslogtreecommitdiff
path: root/libcxx/include/__format/format_context.h
diff options
context:
space:
mode:
Diffstat (limited to 'libcxx/include/__format/format_context.h')
-rw-r--r--libcxx/include/__format/format_context.h88
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