master
  1// -*- C++ -*-
  2//===----------------------------------------------------------------------===//
  3//
  4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  5// See https://llvm.org/LICENSE.txt for license information.
  6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  7//
  8//===----------------------------------------------------------------------===//
  9
 10#ifndef _LIBCPP___FORMAT_FORMAT_CONTEXT_H
 11#define _LIBCPP___FORMAT_FORMAT_CONTEXT_H
 12
 13#include <__concepts/same_as.h>
 14#include <__config>
 15#include <__format/buffer.h>
 16#include <__format/format_arg.h>
 17#include <__format/format_arg_store.h>
 18#include <__format/format_args.h>
 19#include <__format/format_error.h>
 20#include <__fwd/format.h>
 21#include <__iterator/back_insert_iterator.h>
 22#include <__iterator/concepts.h>
 23#include <__memory/addressof.h>
 24#include <__utility/move.h>
 25#include <__variant/monostate.h>
 26
 27#if _LIBCPP_HAS_LOCALIZATION
 28#  include <__locale>
 29#  include <optional>
 30#endif
 31
 32#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 33#  pragma GCC system_header
 34#endif
 35
 36_LIBCPP_PUSH_MACROS
 37#include <__undef_macros>
 38
 39_LIBCPP_BEGIN_NAMESPACE_STD
 40
 41#if _LIBCPP_STD_VER >= 20
 42
 43template <class _OutIt, class _CharT>
 44  requires output_iterator<_OutIt, const _CharT&>
 45class basic_format_context;
 46
 47#  if _LIBCPP_HAS_LOCALIZATION
 48/**
 49 * Helper to create a basic_format_context.
 50 *
 51 * This is needed since the constructor is private.
 52 */
 53template <class _OutIt, class _CharT>
 54_LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT>
 55__format_context_create(_OutIt __out_it,
 56                        basic_format_args<basic_format_context<_OutIt, _CharT>> __args,
 57                        optional<std::locale>&& __loc = nullopt) {
 58  return std::basic_format_context(std::move(__out_it), __args, std::move(__loc));
 59}
 60#  else
 61template <class _OutIt, class _CharT>
 62_LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT>
 63__format_context_create(_OutIt __out_it, basic_format_args<basic_format_context<_OutIt, _CharT>> __args) {
 64  return std::basic_format_context(std::move(__out_it), __args);
 65}
 66#  endif
 67
 68using format_context = basic_format_context<back_insert_iterator<__format::__output_buffer<char>>, char>;
 69#  if _LIBCPP_HAS_WIDE_CHARACTERS
 70using wformat_context = basic_format_context< back_insert_iterator<__format::__output_buffer<wchar_t>>, wchar_t>;
 71#  endif
 72
 73template <class _OutIt, class _CharT>
 74  requires output_iterator<_OutIt, const _CharT&>
 75class _LIBCPP_PREFERRED_NAME(format_context)
 76    _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wformat_context)) basic_format_context {
 77public:
 78  using iterator  = _OutIt;
 79  using char_type = _CharT;
 80  template <class _Tp>
 81  using formatter_type = formatter<_Tp, _CharT>;
 82
 83  _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept {
 84    return __args_.get(__id);
 85  }
 86#  if _LIBCPP_HAS_LOCALIZATION
 87  _LIBCPP_HIDE_FROM_ABI std::locale locale() {
 88    if (!__loc_)
 89      __loc_ = std::locale{};
 90    return *__loc_;
 91  }
 92#  endif
 93  _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); }
 94  _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); }
 95
 96private:
 97  iterator __out_it_;
 98  basic_format_args<basic_format_context> __args_;
 99#  if _LIBCPP_HAS_LOCALIZATION
100
101  // The Standard doesn't specify how the locale is stored.
102  // [format.context]/6
103  // std::locale locale();
104  //   Returns: The locale passed to the formatting function if the latter
105  //   takes one, and std::locale() otherwise.
106  // This is done by storing the locale of the constructor in this optional. If
107  // locale() is called and the optional has no value the value will be created.
108  // This allows the implementation to lazily create the locale.
109  // TODO FMT Validate whether lazy creation is the best solution.
110  optional<std::locale> __loc_;
111
112  template <class _OtherOutIt, class _OtherCharT>
113  friend _LIBCPP_HIDE_FROM_ABI basic_format_context<_OtherOutIt, _OtherCharT> __format_context_create(
114      _OtherOutIt, basic_format_args<basic_format_context<_OtherOutIt, _OtherCharT>>, optional<std::locale>&&);
115
116  // Note: the Standard doesn't specify the required constructors.
117  _LIBCPP_HIDE_FROM_ABI explicit basic_format_context(
118      _OutIt __out_it, basic_format_args<basic_format_context> __args, optional<std::locale>&& __loc)
119      : __out_it_(std::move(__out_it)), __args_(__args), __loc_(std::move(__loc)) {}
120#  else
121  template <class _OtherOutIt, class _OtherCharT>
122  friend _LIBCPP_HIDE_FROM_ABI basic_format_context<_OtherOutIt, _OtherCharT>
123      __format_context_create(_OtherOutIt, basic_format_args<basic_format_context<_OtherOutIt, _OtherCharT>>);
124
125  _LIBCPP_HIDE_FROM_ABI explicit basic_format_context(_OutIt __out_it, basic_format_args<basic_format_context> __args)
126      : __out_it_(std::move(__out_it)), __args_(__args) {}
127#  endif
128
129public:
130  basic_format_context(const basic_format_context&)            = delete;
131  basic_format_context& operator=(const basic_format_context&) = delete;
132};
133
134// A specialization for __retarget_buffer
135//
136// See __retarget_buffer for the motivation for this specialization.
137//
138// This context holds a reference to the instance of the basic_format_context
139// that is retargeted. It converts a formatting argument when it is requested
140// during formatting. It is expected that the usage of the arguments is rare so
141// the lookups are not expected to be used often. An alternative would be to
142// convert all elements during construction.
143//
144// The elements of the retargets context are only used when an underlying
145// formatter uses a locale specific formatting or an formatting argument is
146// part for the format spec. For example
147//   format("{:256:{}}", input, 8);
148// Here the width of an element in input is determined dynamically.
149// Note when the top-level element has no width the retargeting is not needed.
150template <class _CharT>
151class basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> {
152public:
153  using iterator  = typename __format::__retarget_buffer<_CharT>::__iterator;
154  using char_type = _CharT;
155  template <class _Tp>
156  using formatter_type = formatter<_Tp, _CharT>;
157
158  template <class _Context>
159  _LIBCPP_HIDE_FROM_ABI explicit basic_format_context(iterator __out_it, _Context& __ctx)
160      : __out_it_(std::move(__out_it)),
161#  if _LIBCPP_HAS_LOCALIZATION
162        __loc_([](void* __c) { return static_cast<_Context*>(__c)->locale(); }),
163#  endif
164        __ctx_(std::addressof(__ctx)),
165        __arg_([](void* __c, size_t __id) {
166          auto __visitor = [&](auto __arg) -> basic_format_arg<basic_format_context> {
167            if constexpr (same_as<decltype(__arg), monostate>)
168              return {};
169            else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Context>::handle>)
170              // At the moment it's not possible for formatting to use a re-targeted handle.
171              // TODO FMT add this when support is needed.
172              std::__throw_format_error("Re-targeting handle not supported");
173            else
174              return basic_format_arg<basic_format_context>{
175                  __format::__determine_arg_t<basic_format_context, decltype(__arg)>(),
176                  __basic_format_arg_value<basic_format_context>(__arg)};
177          };
178#  if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER
179          return static_cast<_Context*>(__c)->arg(__id).visit(std::move(__visitor));
180#  else
181          _LIBCPP_SUPPRESS_DEPRECATED_PUSH
182          return std::visit_format_arg(std::move(__visitor), static_cast<_Context*>(__c)->arg(__id));
183          _LIBCPP_SUPPRESS_DEPRECATED_POP
184#  endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER
185        }) {
186  }
187
188  _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept {
189    return __arg_(__ctx_, __id);
190  }
191#  if _LIBCPP_HAS_LOCALIZATION
192  _LIBCPP_HIDE_FROM_ABI std::locale locale() { return __loc_(__ctx_); }
193#  endif
194  _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); }
195  _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); }
196
197private:
198  iterator __out_it_;
199
200#  if _LIBCPP_HAS_LOCALIZATION
201  std::locale (*__loc_)(void* __ctx);
202#  endif
203
204  void* __ctx_;
205  basic_format_arg<basic_format_context> (*__arg_)(void* __ctx, size_t __id);
206};
207
208_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_context);
209#endif // _LIBCPP_STD_VER >= 20
210
211_LIBCPP_END_NAMESPACE_STD
212
213_LIBCPP_POP_MACROS
214
215#endif // _LIBCPP___FORMAT_FORMAT_CONTEXT_H