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 <__availability>
14 #include <__config>
15 #include <__format/format_args.h>
16 #include <__format/format_fwd.h>
17 #include <__iterator/concepts.h>
18 #include <concepts>
19 #include <iterator>
20 #include <string>
21 
22 #ifndef _LIBCPP_HAS_NO_LOCALIZATION
23 #include <locale>
24 #include <optional>
25 #endif
26 
27 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
28 #pragma GCC system_header
29 #endif
30 
31 _LIBCPP_PUSH_MACROS
32 #include <__undef_macros>
33 
34 _LIBCPP_BEGIN_NAMESPACE_STD
35 
36 #if _LIBCPP_STD_VER > 17
37 
38 // TODO FMT Remove this once we require compilers with proper C++20 support.
39 // If the compiler has no concepts support, the format header will be disabled.
40 // Without concepts support enable_if needs to be used and that too much effort
41 // to support compilers with partial C++20 support.
42 #if !defined(_LIBCPP_HAS_NO_CONCEPTS)
43 
44 template <class _OutIt, class _CharT>
45 requires output_iterator<_OutIt, const _CharT&>
46 class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_context;
47 
48 #ifndef _LIBCPP_HAS_NO_LOCALIZATION
49 /**
50  * Helper to create a basic_format_context.
51  *
52  * This is needed since the constructor is private.
53  */
54 template <class _OutIt, class _CharT>
55 _LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT>
56 __format_context_create(
57     _OutIt __out_it,
58     basic_format_args<basic_format_context<_OutIt, _CharT>> __args,
59     optional<_VSTD::locale>&& __loc = nullopt) {
60   return _VSTD::basic_format_context(_VSTD::move(__out_it), __args,
61                                      _VSTD::move(__loc));
62 }
63 #else
64 template <class _OutIt, class _CharT>
65 _LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT>
66 __format_context_create(
67     _OutIt __out_it,
68     basic_format_args<basic_format_context<_OutIt, _CharT>> __args) {
69   return _VSTD::basic_format_context(_VSTD::move(__out_it), __args);
70 }
71 #endif
72 
73 // TODO FMT Implement [format.context]/4
74 // [Note 1: For a given type charT, implementations are encouraged to provide a
75 // single instantiation of basic_format_context for appending to
76 // basic_string<charT>, vector<charT>, or any other container with contiguous
77 // storage by wrapping those in temporary objects with a uniform interface
78 // (such as a span<charT>) and polymorphic reallocation. - end note]
79 
80 using format_context = basic_format_context<back_insert_iterator<string>, char>;
81 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
82 using wformat_context = basic_format_context<back_insert_iterator<wstring>, wchar_t>;
83 #endif
84 
85 template <class _OutIt, class _CharT>
86 requires output_iterator<_OutIt, const _CharT&>
87 class
88     // clang-format off
89     _LIBCPP_TEMPLATE_VIS
90     _LIBCPP_AVAILABILITY_FORMAT
91     _LIBCPP_PREFERRED_NAME(format_context)
92     _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wformat_context))
93     // clang-format on
94     basic_format_context {
95 public:
96   using iterator = _OutIt;
97   using char_type = _CharT;
98   template <class _Tp>
99   using formatter_type = formatter<_Tp, _CharT>;
100 
101   basic_format_context(const basic_format_context&) = delete;
102   basic_format_context& operator=(const basic_format_context&) = delete;
103 
104   _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context>
105   arg(size_t __id) const {
106     return __args_.get(__id);
107   }
108 #ifndef _LIBCPP_HAS_NO_LOCALIZATION
109   _LIBCPP_HIDE_FROM_ABI _VSTD::locale locale() {
110     if (!__loc_)
111       __loc_ = _VSTD::locale{};
112     return *__loc_;
113   }
114 #endif
115   _LIBCPP_HIDE_FROM_ABI iterator out() { return __out_it_; }
116   _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = __it; }
117 
118 private:
119   iterator __out_it_;
120   basic_format_args<basic_format_context> __args_;
121 #ifndef _LIBCPP_HAS_NO_LOCALIZATION
122 
123   // The Standard doesn't specify how the locale is stored.
124   // [format.context]/6
125   // std::locale locale();
126   //   Returns: The locale passed to the formatting function if the latter
127   //   takes one, and std::locale() otherwise.
128   // This is done by storing the locale of the constructor in this optional. If
129   // locale() is called and the optional has no value the value will be created.
130   // This allows the implementation to lazily create the locale.
131   // TODO FMT Validate whether lazy creation is the best solution.
132   optional<_VSTD::locale> __loc_;
133 
134   template <class __OutIt, class __CharT>
135   friend _LIBCPP_HIDE_FROM_ABI basic_format_context<__OutIt, __CharT>
136   _VSTD::__format_context_create(
137       __OutIt, basic_format_args<basic_format_context<__OutIt, __CharT>>,
138       optional<_VSTD::locale>&&);
139 
140   // Note: the Standard doesn't specify the required constructors.
141   _LIBCPP_HIDE_FROM_ABI
142   explicit basic_format_context(_OutIt __out_it,
143                                 basic_format_args<basic_format_context> __args,
144                                 optional<_VSTD::locale>&& __loc)
145       : __out_it_(_VSTD::move(__out_it)), __args_(__args),
146         __loc_(_VSTD::move(__loc)) {}
147 #else
148   template <class __OutIt, class __CharT>
149   friend _LIBCPP_HIDE_FROM_ABI basic_format_context<__OutIt, __CharT>
150       _VSTD::__format_context_create(
151           __OutIt, basic_format_args<basic_format_context<__OutIt, __CharT>>);
152 
153   _LIBCPP_HIDE_FROM_ABI
154   explicit basic_format_context(_OutIt __out_it,
155                                 basic_format_args<basic_format_context> __args)
156       : __out_it_(_VSTD::move(__out_it)), __args_(__args) {}
157 #endif
158 };
159 
160 #endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
161 
162 #endif //_LIBCPP_STD_VER > 17
163 
164 _LIBCPP_END_NAMESPACE_STD
165 
166 _LIBCPP_POP_MACROS
167 
168 #endif // _LIBCPP___FORMAT_FORMAT_CONTEXT_H
169