88#ifndef FMT_ARGS_H_
99#define FMT_ARGS_H_
1010
11- #include < functional> // std::reference_wrapper
12- #include < memory> // std::unique_ptr
13- #include < vector>
11+ #ifndef FMT_MODULE
12+ # include < functional> // std::reference_wrapper
13+ # include < memory> // std::unique_ptr
14+ # include < vector>
15+ #endif
1416
15- #include " core .h"
17+ #include " format .h" // std_string_view
1618
1719FMT_BEGIN_NAMESPACE
18-
1920namespace detail {
2021
2122template <typename T> struct is_reference_wrapper : std::false_type {};
@@ -28,15 +29,18 @@ auto unwrap(const std::reference_wrapper<T>& v) -> const T& {
2829 return static_cast <const T&>(v);
2930}
3031
31- class dynamic_arg_list {
32- // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
33- // templates it doesn't complain about inability to deduce single translation
34- // unit for placing vtable. So storage_node_base is made a fake template.
35- template <typename = void > struct node {
36- virtual ~node () = default ;
37- std::unique_ptr<node<>> next;
38- };
32+ // node is defined outside dynamic_arg_list to workaround a C2504 bug in MSVC
33+ // 2022 (v17.10.0).
34+ //
35+ // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
36+ // templates it doesn't complain about inability to deduce single translation
37+ // unit for placing vtable. So node is made a fake template.
38+ template <typename = void > struct node {
39+ virtual ~node () = default ;
40+ std::unique_ptr<node<>> next;
41+ };
3942
43+ class dynamic_arg_list {
4044 template <typename T> struct typed_node : node<> {
4145 T value;
4246
@@ -62,28 +66,18 @@ class dynamic_arg_list {
6266} // namespace detail
6367
6468/* *
65- \rst
66- A dynamic version of `fmt::format_arg_store`.
67- It's equipped with a storage to potentially temporary objects which lifetimes
68- could be shorter than the format arguments object.
69-
70- It can be implicitly converted into `~fmt::basic_format_args` for passing
71- into type-erased formatting functions such as `~fmt::vformat`.
72- \endrst
69+ * A dynamic list of formatting arguments with storage.
70+ *
71+ * It can be implicitly converted into `fmt::basic_format_args` for passing
72+ * into type-erased formatting functions such as `fmt::vformat`.
7373 */
74- template <typename Context>
75- class dynamic_format_arg_store
76- #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
77- // Workaround a GCC template argument substitution bug.
78- : public basic_format_args<Context>
79- #endif
80- {
74+ template <typename Context> class dynamic_format_arg_store {
8175 private:
8276 using char_type = typename Context::char_type;
8377
8478 template <typename T> struct need_copy {
8579 static constexpr detail::type mapped_type =
86- detail::mapped_type_constant<T, Context >::value;
80+ detail::mapped_type_constant<T, char_type >::value;
8781
8882 enum {
8983 value = !(detail::is_reference_wrapper<T>::value ||
@@ -96,7 +90,7 @@ class dynamic_format_arg_store
9690 };
9791
9892 template <typename T>
99- using stored_type = conditional_t <
93+ using stored_t = conditional_t <
10094 std::is_convertible<T, std::basic_string<char_type>>::value &&
10195 !detail::is_reference_wrapper<T>::value,
10296 std::basic_string<char_type>, T>;
@@ -111,80 +105,72 @@ class dynamic_format_arg_store
111105
112106 friend class basic_format_args <Context>;
113107
114- auto get_types () const -> unsigned long long {
115- return detail::is_unpacked_bit | data_.size () |
116- (named_info_.empty ()
117- ? 0ULL
118- : static_cast <unsigned long long >(detail::has_named_args_bit));
119- }
120-
121108 auto data () const -> const basic_format_arg<Context>* {
122109 return named_info_.empty () ? data_.data () : data_.data () + 1 ;
123110 }
124111
125112 template <typename T> void emplace_arg (const T& arg) {
126- data_.emplace_back (detail::make_arg<Context>( arg) );
113+ data_.emplace_back (arg);
127114 }
128115
129116 template <typename T>
130117 void emplace_arg (const detail::named_arg<char_type, T>& arg) {
131- if (named_info_.empty ()) {
132- constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr };
133- data_.insert (data_.begin (), {zero_ptr, 0 });
134- }
135- data_.emplace_back (detail::make_arg<Context>(detail::unwrap (arg.value )));
118+ if (named_info_.empty ())
119+ data_.insert (data_.begin (), basic_format_arg<Context>(nullptr , 0 ));
120+ data_.emplace_back (detail::unwrap (arg.value ));
136121 auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
137122 data->pop_back ();
138123 };
139124 std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype (pop_one)>
140125 guard{&data_, pop_one};
141126 named_info_.push_back ({arg.name , static_cast <int >(data_.size () - 2u )});
142- data_[0 ]. value_ . named_args = {named_info_.data (), named_info_.size ()};
127+ data_[0 ] = {named_info_.data (), named_info_.size ()};
143128 guard.release ();
144129 }
145130
146131 public:
147132 constexpr dynamic_format_arg_store () = default;
148133
134+ operator basic_format_args<Context>() const {
135+ return basic_format_args<Context>(data (), static_cast <int >(data_.size ()),
136+ !named_info_.empty ());
137+ }
138+
149139 /* *
150- \rst
151- Adds an argument into the dynamic store for later passing to a formatting
152- function.
153-
154- Note that custom types and string types (but not string views) are copied
155- into the store dynamically allocating memory if necessary.
156-
157- **Example**::
158-
159- fmt::dynamic_format_arg_store<fmt::format_context> store;
160- store.push_back(42);
161- store.push_back("abc");
162- store.push_back(1.5f);
163- std::string result = fmt::vformat("{} and {} and {}", store);
164- \endrst
165- */
140+ * Adds an argument into the dynamic store for later passing to a formatting
141+ * function.
142+ *
143+ * Note that custom types and string types (but not string views) are copied
144+ * into the store dynamically allocating memory if necessary.
145+ *
146+ * **Example**:
147+ *
148+ * fmt::dynamic_format_arg_store<fmt::format_context> store;
149+ * store.push_back(42);
150+ * store.push_back("abc");
151+ * store.push_back(1.5f);
152+ * std::string result = fmt::vformat("{} and {} and {}", store);
153+ */
166154 template <typename T> void push_back (const T& arg) {
167155 if (detail::const_check (need_copy<T>::value))
168- emplace_arg (dynamic_args_.push <stored_type <T>>(arg));
156+ emplace_arg (dynamic_args_.push <stored_t <T>>(arg));
169157 else
170158 emplace_arg (detail::unwrap (arg));
171159 }
172160
173161 /* *
174- \rst
175- Adds a reference to the argument into the dynamic store for later passing to
176- a formatting function.
177-
178- **Example**::
179-
180- fmt::dynamic_format_arg_store<fmt::format_context> store;
181- char band[] = "Rolling Stones";
182- store.push_back(std::cref(band));
183- band[9] = 'c'; // Changing str affects the output.
184- std::string result = fmt::vformat("{}", store);
185- // result == "Rolling Scones"
186- \endrst
187- */
162+ * Adds a reference to the argument into the dynamic store for later passing
163+ * to a formatting function.
164+ *
165+ * **Example**:
166+ *
167+ * fmt::dynamic_format_arg_store<fmt::format_context> store;
168+ * char band[] = "Rolling Stones";
169+ * store.push_back(std::cref(band));
170+ * band[9] = 'c'; // Changing str affects the output.
171+ * std::string result = fmt::vformat("{}", store);
172+ * // result == "Rolling Scones"
173+ */
188174 template <typename T> void push_back (std::reference_wrapper<T> arg) {
189175 static_assert (
190176 need_copy<T>::value,
@@ -193,41 +179,40 @@ class dynamic_format_arg_store
193179 }
194180
195181 /* *
196- Adds named argument into the dynamic store for later passing to a formatting
197- function. `` std::reference_wrapper`` is supported to avoid copying of the
198- argument. The name is always copied into the store.
199- */
182+ * Adds named argument into the dynamic store for later passing to a
183+ * formatting function. `std::reference_wrapper` is supported to avoid
184+ * copying of the argument. The name is always copied into the store.
185+ */
200186 template <typename T>
201187 void push_back (const detail::named_arg<char_type, T>& arg) {
202188 const char_type* arg_name =
203189 dynamic_args_.push <std::basic_string<char_type>>(arg.name ).c_str ();
204190 if (detail::const_check (need_copy<T>::value)) {
205191 emplace_arg (
206- fmt::arg (arg_name, dynamic_args_.push <stored_type <T>>(arg.value )));
192+ fmt::arg (arg_name, dynamic_args_.push <stored_t <T>>(arg.value )));
207193 } else {
208194 emplace_arg (fmt::arg (arg_name, arg.value ));
209195 }
210196 }
211197
212- /* * Erase all elements from the store */
198+ // / Erase all elements from the store.
213199 void clear () {
214200 data_.clear ();
215201 named_info_.clear ();
216- dynamic_args_ = detail::dynamic_arg_list () ;
202+ dynamic_args_ = {} ;
217203 }
218204
219- /* *
220- \rst
221- Reserves space to store at least *new_cap* arguments including
222- *new_cap_named* named arguments.
223- \endrst
224- */
205+ // / Reserves space to store at least `new_cap` arguments including
206+ // / `new_cap_named` named arguments.
225207 void reserve (size_t new_cap, size_t new_cap_named) {
226208 FMT_ASSERT (new_cap >= new_cap_named,
227- " Set of arguments includes set of named arguments" );
209+ " set of arguments includes set of named arguments" );
228210 data_.reserve (new_cap);
229211 named_info_.reserve (new_cap_named);
230212 }
213+
214+ // / Returns the number of elements in the store.
215+ size_t size () const noexcept { return data_.size (); }
231216};
232217
233218FMT_END_NAMESPACE
0 commit comments