1349cc55cSDimitry Andric // -*- C++ -*- 2349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 3349cc55cSDimitry Andric // 4349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 6349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7349cc55cSDimitry Andric // 8349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 9349cc55cSDimitry Andric 10349cc55cSDimitry Andric #ifndef _LIBCPP___FORMAT_FORMAT_CONTEXT_H 11349cc55cSDimitry Andric #define _LIBCPP___FORMAT_FORMAT_CONTEXT_H 12349cc55cSDimitry Andric 13bdd1243dSDimitry Andric #include <__concepts/same_as.h> 14349cc55cSDimitry Andric #include <__config> 1581ad6265SDimitry Andric #include <__format/buffer.h> 16bdd1243dSDimitry Andric #include <__format/format_arg.h> 17bdd1243dSDimitry Andric #include <__format/format_arg_store.h> 18349cc55cSDimitry Andric #include <__format/format_args.h> 19bdd1243dSDimitry Andric #include <__format/format_error.h> 20*0fca6ea1SDimitry Andric #include <__fwd/format.h> 210eae32dcSDimitry Andric #include <__iterator/back_insert_iterator.h> 22349cc55cSDimitry Andric #include <__iterator/concepts.h> 23bdd1243dSDimitry Andric #include <__memory/addressof.h> 2481ad6265SDimitry Andric #include <__utility/move.h> 25bdd1243dSDimitry Andric #include <__variant/monostate.h> 2681ad6265SDimitry Andric #include <cstddef> 27349cc55cSDimitry Andric 28349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_LOCALIZATION 29*0fca6ea1SDimitry Andric # include <__locale> 30349cc55cSDimitry Andric # include <optional> 31349cc55cSDimitry Andric #endif 32349cc55cSDimitry Andric 33349cc55cSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 34349cc55cSDimitry Andric # pragma GCC system_header 35349cc55cSDimitry Andric #endif 36349cc55cSDimitry Andric 37b3edf446SDimitry Andric _LIBCPP_PUSH_MACROS 38b3edf446SDimitry Andric #include <__undef_macros> 39b3edf446SDimitry Andric 40349cc55cSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 41349cc55cSDimitry Andric 4206c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20 43349cc55cSDimitry Andric 44349cc55cSDimitry Andric template <class _OutIt, class _CharT> 45349cc55cSDimitry Andric requires output_iterator<_OutIt, const _CharT&> 4606c3fb27SDimitry Andric class _LIBCPP_TEMPLATE_VIS basic_format_context; 47349cc55cSDimitry Andric 48349cc55cSDimitry Andric # ifndef _LIBCPP_HAS_NO_LOCALIZATION 49349cc55cSDimitry Andric /** 50349cc55cSDimitry Andric * Helper to create a basic_format_context. 51349cc55cSDimitry Andric * 52349cc55cSDimitry Andric * This is needed since the constructor is private. 53349cc55cSDimitry Andric */ 54349cc55cSDimitry Andric template <class _OutIt, class _CharT> 55349cc55cSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT> 56cb14a3feSDimitry Andric __format_context_create(_OutIt __out_it, 57349cc55cSDimitry Andric basic_format_args<basic_format_context<_OutIt, _CharT>> __args, 585f757f3fSDimitry Andric optional<std::locale>&& __loc = nullopt) { 595f757f3fSDimitry Andric return std::basic_format_context(std::move(__out_it), __args, std::move(__loc)); 60349cc55cSDimitry Andric } 61349cc55cSDimitry Andric # else 62349cc55cSDimitry Andric template <class _OutIt, class _CharT> 63349cc55cSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT> 64cb14a3feSDimitry Andric __format_context_create(_OutIt __out_it, basic_format_args<basic_format_context<_OutIt, _CharT>> __args) { 655f757f3fSDimitry Andric return std::basic_format_context(std::move(__out_it), __args); 66349cc55cSDimitry Andric } 67349cc55cSDimitry Andric # endif 68349cc55cSDimitry Andric 69cb14a3feSDimitry Andric using format_context = basic_format_context<back_insert_iterator<__format::__output_buffer<char>>, char>; 70349cc55cSDimitry Andric # ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS 71cb14a3feSDimitry Andric using wformat_context = basic_format_context< back_insert_iterator<__format::__output_buffer<wchar_t>>, wchar_t>; 72349cc55cSDimitry Andric # endif 73349cc55cSDimitry Andric 74349cc55cSDimitry Andric template <class _OutIt, class _CharT> 75349cc55cSDimitry Andric requires output_iterator<_OutIt, const _CharT&> 76349cc55cSDimitry Andric class 77349cc55cSDimitry Andric // clang-format off 78349cc55cSDimitry Andric _LIBCPP_TEMPLATE_VIS 79349cc55cSDimitry Andric _LIBCPP_PREFERRED_NAME(format_context) 80349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wformat_context)) 81349cc55cSDimitry Andric // clang-format on 82349cc55cSDimitry Andric basic_format_context { 83349cc55cSDimitry Andric public: 84349cc55cSDimitry Andric using iterator = _OutIt; 85349cc55cSDimitry Andric using char_type = _CharT; 86349cc55cSDimitry Andric template <class _Tp> 87349cc55cSDimitry Andric using formatter_type = formatter<_Tp, _CharT>; 88349cc55cSDimitry Andric 89cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept { 90349cc55cSDimitry Andric return __args_.get(__id); 91349cc55cSDimitry Andric } 92349cc55cSDimitry Andric # ifndef _LIBCPP_HAS_NO_LOCALIZATION 935f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI std::locale locale() { 94349cc55cSDimitry Andric if (!__loc_) 955f757f3fSDimitry Andric __loc_ = std::locale{}; 96349cc55cSDimitry Andric return *__loc_; 97349cc55cSDimitry Andric } 98349cc55cSDimitry Andric # endif 99bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); } 100bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); } 101349cc55cSDimitry Andric 102349cc55cSDimitry Andric private: 103349cc55cSDimitry Andric iterator __out_it_; 104349cc55cSDimitry Andric basic_format_args<basic_format_context> __args_; 105349cc55cSDimitry Andric # ifndef _LIBCPP_HAS_NO_LOCALIZATION 106349cc55cSDimitry Andric 107349cc55cSDimitry Andric // The Standard doesn't specify how the locale is stored. 108349cc55cSDimitry Andric // [format.context]/6 109349cc55cSDimitry Andric // std::locale locale(); 110349cc55cSDimitry Andric // Returns: The locale passed to the formatting function if the latter 111349cc55cSDimitry Andric // takes one, and std::locale() otherwise. 112349cc55cSDimitry Andric // This is done by storing the locale of the constructor in this optional. If 113349cc55cSDimitry Andric // locale() is called and the optional has no value the value will be created. 114349cc55cSDimitry Andric // This allows the implementation to lazily create the locale. 115349cc55cSDimitry Andric // TODO FMT Validate whether lazy creation is the best solution. 1165f757f3fSDimitry Andric optional<std::locale> __loc_; 117349cc55cSDimitry Andric 11806c3fb27SDimitry Andric template <class _OtherOutIt, class _OtherCharT> 119cb14a3feSDimitry Andric friend _LIBCPP_HIDE_FROM_ABI basic_format_context<_OtherOutIt, _OtherCharT> __format_context_create( 120cb14a3feSDimitry Andric _OtherOutIt, basic_format_args<basic_format_context<_OtherOutIt, _OtherCharT>>, optional<std::locale>&&); 121349cc55cSDimitry Andric 122349cc55cSDimitry Andric // Note: the Standard doesn't specify the required constructors. 123cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit basic_format_context( 124cb14a3feSDimitry Andric _OutIt __out_it, basic_format_args<basic_format_context> __args, optional<std::locale>&& __loc) 125cb14a3feSDimitry Andric : __out_it_(std::move(__out_it)), __args_(__args), __loc_(std::move(__loc)) {} 126349cc55cSDimitry Andric # else 12706c3fb27SDimitry Andric template <class _OtherOutIt, class _OtherCharT> 12806c3fb27SDimitry Andric friend _LIBCPP_HIDE_FROM_ABI basic_format_context<_OtherOutIt, _OtherCharT> 12906c3fb27SDimitry Andric __format_context_create(_OtherOutIt, basic_format_args<basic_format_context<_OtherOutIt, _OtherCharT>>); 130349cc55cSDimitry Andric 131cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit basic_format_context(_OutIt __out_it, basic_format_args<basic_format_context> __args) 1325f757f3fSDimitry Andric : __out_it_(std::move(__out_it)), __args_(__args) {} 133349cc55cSDimitry Andric # endif 134*0fca6ea1SDimitry Andric 135*0fca6ea1SDimitry Andric basic_format_context(const basic_format_context&) = delete; 136*0fca6ea1SDimitry Andric basic_format_context& operator=(const basic_format_context&) = delete; 137349cc55cSDimitry Andric }; 138349cc55cSDimitry Andric 139bdd1243dSDimitry Andric // A specialization for __retarget_buffer 140bdd1243dSDimitry Andric // 141bdd1243dSDimitry Andric // See __retarget_buffer for the motivation for this specialization. 142bdd1243dSDimitry Andric // 143bdd1243dSDimitry Andric // This context holds a reference to the instance of the basic_format_context 144bdd1243dSDimitry Andric // that is retargeted. It converts a formatting argument when it is requested 145bdd1243dSDimitry Andric // during formatting. It is expected that the usage of the arguments is rare so 146bdd1243dSDimitry Andric // the lookups are not expected to be used often. An alternative would be to 147bdd1243dSDimitry Andric // convert all elements during construction. 148bdd1243dSDimitry Andric // 149bdd1243dSDimitry Andric // The elements of the retargets context are only used when an underlying 150bdd1243dSDimitry Andric // formatter uses a locale specific formatting or an formatting argument is 151bdd1243dSDimitry Andric // part for the format spec. For example 152bdd1243dSDimitry Andric // format("{:256:{}}", input, 8); 153bdd1243dSDimitry Andric // Here the width of an element in input is determined dynamically. 154bdd1243dSDimitry Andric // Note when the top-level element has no width the retargeting is not needed. 155bdd1243dSDimitry Andric template <class _CharT> 156cb14a3feSDimitry Andric class _LIBCPP_TEMPLATE_VIS basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> { 157bdd1243dSDimitry Andric public: 158bdd1243dSDimitry Andric using iterator = typename __format::__retarget_buffer<_CharT>::__iterator; 159bdd1243dSDimitry Andric using char_type = _CharT; 160bdd1243dSDimitry Andric template <class _Tp> 161bdd1243dSDimitry Andric using formatter_type = formatter<_Tp, _CharT>; 162bdd1243dSDimitry Andric 163bdd1243dSDimitry Andric template <class _Context> 164bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit basic_format_context(iterator __out_it, _Context& __ctx) 165bdd1243dSDimitry Andric : __out_it_(std::move(__out_it)), 166bdd1243dSDimitry Andric # ifndef _LIBCPP_HAS_NO_LOCALIZATION 167bdd1243dSDimitry Andric __loc_([](void* __c) { return static_cast<_Context*>(__c)->locale(); }), 168bdd1243dSDimitry Andric # endif 169bdd1243dSDimitry Andric __ctx_(std::addressof(__ctx)), 170bdd1243dSDimitry Andric __arg_([](void* __c, size_t __id) { 171*0fca6ea1SDimitry Andric auto __visitor = [&](auto __arg) -> basic_format_arg<basic_format_context> { 172bdd1243dSDimitry Andric if constexpr (same_as<decltype(__arg), monostate>) 173bdd1243dSDimitry Andric return {}; 174bdd1243dSDimitry Andric else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Context>::handle>) 175bdd1243dSDimitry Andric // At the moment it's not possible for formatting to use a re-targeted handle. 176bdd1243dSDimitry Andric // TODO FMT add this when support is needed. 177bdd1243dSDimitry Andric std::__throw_format_error("Re-targeting handle not supported"); 178bdd1243dSDimitry Andric else 179bdd1243dSDimitry Andric return basic_format_arg<basic_format_context>{ 180bdd1243dSDimitry Andric __format::__determine_arg_t<basic_format_context, decltype(__arg)>(), 181bdd1243dSDimitry Andric __basic_format_arg_value<basic_format_context>(__arg)}; 182*0fca6ea1SDimitry Andric }; 183*0fca6ea1SDimitry Andric # if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) 184*0fca6ea1SDimitry Andric return static_cast<_Context*>(__c)->arg(__id).visit(std::move(__visitor)); 185*0fca6ea1SDimitry Andric # else 186*0fca6ea1SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH 187*0fca6ea1SDimitry Andric return std::visit_format_arg(std::move(__visitor), static_cast<_Context*>(__c)->arg(__id)); 188*0fca6ea1SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP 189*0fca6ea1SDimitry Andric # endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) 190bdd1243dSDimitry Andric }) { 191bdd1243dSDimitry Andric } 192bdd1243dSDimitry Andric 193bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept { 194bdd1243dSDimitry Andric return __arg_(__ctx_, __id); 195bdd1243dSDimitry Andric } 196bdd1243dSDimitry Andric # ifndef _LIBCPP_HAS_NO_LOCALIZATION 1975f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI std::locale locale() { return __loc_(__ctx_); } 198bdd1243dSDimitry Andric # endif 199bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); } 200bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); } 201bdd1243dSDimitry Andric 202bdd1243dSDimitry Andric private: 203bdd1243dSDimitry Andric iterator __out_it_; 204bdd1243dSDimitry Andric 205bdd1243dSDimitry Andric # ifndef _LIBCPP_HAS_NO_LOCALIZATION 206bdd1243dSDimitry Andric std::locale (*__loc_)(void* __ctx); 207bdd1243dSDimitry Andric # endif 208bdd1243dSDimitry Andric 209bdd1243dSDimitry Andric void* __ctx_; 210bdd1243dSDimitry Andric basic_format_arg<basic_format_context> (*__arg_)(void* __ctx, size_t __id); 211bdd1243dSDimitry Andric }; 212bdd1243dSDimitry Andric 213bdd1243dSDimitry Andric _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_context); 21406c3fb27SDimitry Andric #endif //_LIBCPP_STD_VER >= 20 215349cc55cSDimitry Andric 216349cc55cSDimitry Andric _LIBCPP_END_NAMESPACE_STD 217349cc55cSDimitry Andric 218b3edf446SDimitry Andric _LIBCPP_POP_MACROS 219b3edf446SDimitry Andric 220349cc55cSDimitry Andric #endif // _LIBCPP___FORMAT_FORMAT_CONTEXT_H 221