xref: /aosp_15_r20/external/fmtlib/include/fmt/args.h (revision 5c90c05cd622c0a81b57953a4d343e0e489f2e08)
1*5c90c05cSAndroid Build Coastguard Worker // Formatting library for C++ - dynamic argument lists
2*5c90c05cSAndroid Build Coastguard Worker //
3*5c90c05cSAndroid Build Coastguard Worker // Copyright (c) 2012 - present, Victor Zverovich
4*5c90c05cSAndroid Build Coastguard Worker // All rights reserved.
5*5c90c05cSAndroid Build Coastguard Worker //
6*5c90c05cSAndroid Build Coastguard Worker // For the license information refer to format.h.
7*5c90c05cSAndroid Build Coastguard Worker 
8*5c90c05cSAndroid Build Coastguard Worker #ifndef FMT_ARGS_H_
9*5c90c05cSAndroid Build Coastguard Worker #define FMT_ARGS_H_
10*5c90c05cSAndroid Build Coastguard Worker 
11*5c90c05cSAndroid Build Coastguard Worker #ifndef FMT_MODULE
12*5c90c05cSAndroid Build Coastguard Worker #  include <functional>  // std::reference_wrapper
13*5c90c05cSAndroid Build Coastguard Worker #  include <memory>      // std::unique_ptr
14*5c90c05cSAndroid Build Coastguard Worker #  include <vector>
15*5c90c05cSAndroid Build Coastguard Worker #endif
16*5c90c05cSAndroid Build Coastguard Worker 
17*5c90c05cSAndroid Build Coastguard Worker #include "format.h"  // std_string_view
18*5c90c05cSAndroid Build Coastguard Worker 
19*5c90c05cSAndroid Build Coastguard Worker FMT_BEGIN_NAMESPACE
20*5c90c05cSAndroid Build Coastguard Worker namespace detail {
21*5c90c05cSAndroid Build Coastguard Worker 
22*5c90c05cSAndroid Build Coastguard Worker template <typename T> struct is_reference_wrapper : std::false_type {};
23*5c90c05cSAndroid Build Coastguard Worker template <typename T>
24*5c90c05cSAndroid Build Coastguard Worker struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
25*5c90c05cSAndroid Build Coastguard Worker 
26*5c90c05cSAndroid Build Coastguard Worker template <typename T> auto unwrap(const T& v) -> const T& { return v; }
27*5c90c05cSAndroid Build Coastguard Worker template <typename T>
28*5c90c05cSAndroid Build Coastguard Worker auto unwrap(const std::reference_wrapper<T>& v) -> const T& {
29*5c90c05cSAndroid Build Coastguard Worker   return static_cast<const T&>(v);
30*5c90c05cSAndroid Build Coastguard Worker }
31*5c90c05cSAndroid Build Coastguard Worker 
32*5c90c05cSAndroid Build Coastguard Worker // node is defined outside dynamic_arg_list to workaround a C2504 bug in MSVC
33*5c90c05cSAndroid Build Coastguard Worker // 2022 (v17.10.0).
34*5c90c05cSAndroid Build Coastguard Worker //
35*5c90c05cSAndroid Build Coastguard Worker // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
36*5c90c05cSAndroid Build Coastguard Worker // templates it doesn't complain about inability to deduce single translation
37*5c90c05cSAndroid Build Coastguard Worker // unit for placing vtable. So node is made a fake template.
38*5c90c05cSAndroid Build Coastguard Worker template <typename = void> struct node {
39*5c90c05cSAndroid Build Coastguard Worker   virtual ~node() = default;
40*5c90c05cSAndroid Build Coastguard Worker   std::unique_ptr<node<>> next;
41*5c90c05cSAndroid Build Coastguard Worker };
42*5c90c05cSAndroid Build Coastguard Worker 
43*5c90c05cSAndroid Build Coastguard Worker class dynamic_arg_list {
44*5c90c05cSAndroid Build Coastguard Worker   template <typename T> struct typed_node : node<> {
45*5c90c05cSAndroid Build Coastguard Worker     T value;
46*5c90c05cSAndroid Build Coastguard Worker 
47*5c90c05cSAndroid Build Coastguard Worker     template <typename Arg>
48*5c90c05cSAndroid Build Coastguard Worker     FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
49*5c90c05cSAndroid Build Coastguard Worker 
50*5c90c05cSAndroid Build Coastguard Worker     template <typename Char>
51*5c90c05cSAndroid Build Coastguard Worker     FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
52*5c90c05cSAndroid Build Coastguard Worker         : value(arg.data(), arg.size()) {}
53*5c90c05cSAndroid Build Coastguard Worker   };
54*5c90c05cSAndroid Build Coastguard Worker 
55*5c90c05cSAndroid Build Coastguard Worker   std::unique_ptr<node<>> head_;
56*5c90c05cSAndroid Build Coastguard Worker 
57*5c90c05cSAndroid Build Coastguard Worker  public:
58*5c90c05cSAndroid Build Coastguard Worker   template <typename T, typename Arg> auto push(const Arg& arg) -> const T& {
59*5c90c05cSAndroid Build Coastguard Worker     auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
60*5c90c05cSAndroid Build Coastguard Worker     auto& value = new_node->value;
61*5c90c05cSAndroid Build Coastguard Worker     new_node->next = std::move(head_);
62*5c90c05cSAndroid Build Coastguard Worker     head_ = std::move(new_node);
63*5c90c05cSAndroid Build Coastguard Worker     return value;
64*5c90c05cSAndroid Build Coastguard Worker   }
65*5c90c05cSAndroid Build Coastguard Worker };
66*5c90c05cSAndroid Build Coastguard Worker }  // namespace detail
67*5c90c05cSAndroid Build Coastguard Worker 
68*5c90c05cSAndroid Build Coastguard Worker /**
69*5c90c05cSAndroid Build Coastguard Worker  * A dynamic list of formatting arguments with storage.
70*5c90c05cSAndroid Build Coastguard Worker  *
71*5c90c05cSAndroid Build Coastguard Worker  * It can be implicitly converted into `fmt::basic_format_args` for passing
72*5c90c05cSAndroid Build Coastguard Worker  * into type-erased formatting functions such as `fmt::vformat`.
73*5c90c05cSAndroid Build Coastguard Worker  */
74*5c90c05cSAndroid Build Coastguard Worker template <typename Context> class dynamic_format_arg_store {
75*5c90c05cSAndroid Build Coastguard Worker  private:
76*5c90c05cSAndroid Build Coastguard Worker   using char_type = typename Context::char_type;
77*5c90c05cSAndroid Build Coastguard Worker 
78*5c90c05cSAndroid Build Coastguard Worker   template <typename T> struct need_copy {
79*5c90c05cSAndroid Build Coastguard Worker     static constexpr detail::type mapped_type =
80*5c90c05cSAndroid Build Coastguard Worker         detail::mapped_type_constant<T, char_type>::value;
81*5c90c05cSAndroid Build Coastguard Worker 
82*5c90c05cSAndroid Build Coastguard Worker     enum {
83*5c90c05cSAndroid Build Coastguard Worker       value = !(detail::is_reference_wrapper<T>::value ||
84*5c90c05cSAndroid Build Coastguard Worker                 std::is_same<T, basic_string_view<char_type>>::value ||
85*5c90c05cSAndroid Build Coastguard Worker                 std::is_same<T, detail::std_string_view<char_type>>::value ||
86*5c90c05cSAndroid Build Coastguard Worker                 (mapped_type != detail::type::cstring_type &&
87*5c90c05cSAndroid Build Coastguard Worker                  mapped_type != detail::type::string_type &&
88*5c90c05cSAndroid Build Coastguard Worker                  mapped_type != detail::type::custom_type))
89*5c90c05cSAndroid Build Coastguard Worker     };
90*5c90c05cSAndroid Build Coastguard Worker   };
91*5c90c05cSAndroid Build Coastguard Worker 
92*5c90c05cSAndroid Build Coastguard Worker   template <typename T>
93*5c90c05cSAndroid Build Coastguard Worker   using stored_t = conditional_t<
94*5c90c05cSAndroid Build Coastguard Worker       std::is_convertible<T, std::basic_string<char_type>>::value &&
95*5c90c05cSAndroid Build Coastguard Worker           !detail::is_reference_wrapper<T>::value,
96*5c90c05cSAndroid Build Coastguard Worker       std::basic_string<char_type>, T>;
97*5c90c05cSAndroid Build Coastguard Worker 
98*5c90c05cSAndroid Build Coastguard Worker   // Storage of basic_format_arg must be contiguous.
99*5c90c05cSAndroid Build Coastguard Worker   std::vector<basic_format_arg<Context>> data_;
100*5c90c05cSAndroid Build Coastguard Worker   std::vector<detail::named_arg_info<char_type>> named_info_;
101*5c90c05cSAndroid Build Coastguard Worker 
102*5c90c05cSAndroid Build Coastguard Worker   // Storage of arguments not fitting into basic_format_arg must grow
103*5c90c05cSAndroid Build Coastguard Worker   // without relocation because items in data_ refer to it.
104*5c90c05cSAndroid Build Coastguard Worker   detail::dynamic_arg_list dynamic_args_;
105*5c90c05cSAndroid Build Coastguard Worker 
106*5c90c05cSAndroid Build Coastguard Worker   friend class basic_format_args<Context>;
107*5c90c05cSAndroid Build Coastguard Worker 
108*5c90c05cSAndroid Build Coastguard Worker   auto data() const -> const basic_format_arg<Context>* {
109*5c90c05cSAndroid Build Coastguard Worker     return named_info_.empty() ? data_.data() : data_.data() + 1;
110*5c90c05cSAndroid Build Coastguard Worker   }
111*5c90c05cSAndroid Build Coastguard Worker 
112*5c90c05cSAndroid Build Coastguard Worker   template <typename T> void emplace_arg(const T& arg) {
113*5c90c05cSAndroid Build Coastguard Worker     data_.emplace_back(arg);
114*5c90c05cSAndroid Build Coastguard Worker   }
115*5c90c05cSAndroid Build Coastguard Worker 
116*5c90c05cSAndroid Build Coastguard Worker   template <typename T>
117*5c90c05cSAndroid Build Coastguard Worker   void emplace_arg(const detail::named_arg<char_type, T>& arg) {
118*5c90c05cSAndroid Build Coastguard Worker     if (named_info_.empty())
119*5c90c05cSAndroid Build Coastguard Worker       data_.insert(data_.begin(), basic_format_arg<Context>(nullptr, 0));
120*5c90c05cSAndroid Build Coastguard Worker     data_.emplace_back(detail::unwrap(arg.value));
121*5c90c05cSAndroid Build Coastguard Worker     auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
122*5c90c05cSAndroid Build Coastguard Worker       data->pop_back();
123*5c90c05cSAndroid Build Coastguard Worker     };
124*5c90c05cSAndroid Build Coastguard Worker     std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
125*5c90c05cSAndroid Build Coastguard Worker         guard{&data_, pop_one};
126*5c90c05cSAndroid Build Coastguard Worker     named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
127*5c90c05cSAndroid Build Coastguard Worker     data_[0] = {named_info_.data(), named_info_.size()};
128*5c90c05cSAndroid Build Coastguard Worker     guard.release();
129*5c90c05cSAndroid Build Coastguard Worker   }
130*5c90c05cSAndroid Build Coastguard Worker 
131*5c90c05cSAndroid Build Coastguard Worker  public:
132*5c90c05cSAndroid Build Coastguard Worker   constexpr dynamic_format_arg_store() = default;
133*5c90c05cSAndroid Build Coastguard Worker 
134*5c90c05cSAndroid Build Coastguard Worker   operator basic_format_args<Context>() const {
135*5c90c05cSAndroid Build Coastguard Worker     return basic_format_args<Context>(data(), static_cast<int>(data_.size()),
136*5c90c05cSAndroid Build Coastguard Worker                                       !named_info_.empty());
137*5c90c05cSAndroid Build Coastguard Worker   }
138*5c90c05cSAndroid Build Coastguard Worker 
139*5c90c05cSAndroid Build Coastguard Worker   /**
140*5c90c05cSAndroid Build Coastguard Worker    * Adds an argument into the dynamic store for later passing to a formatting
141*5c90c05cSAndroid Build Coastguard Worker    * function.
142*5c90c05cSAndroid Build Coastguard Worker    *
143*5c90c05cSAndroid Build Coastguard Worker    * Note that custom types and string types (but not string views) are copied
144*5c90c05cSAndroid Build Coastguard Worker    * into the store dynamically allocating memory if necessary.
145*5c90c05cSAndroid Build Coastguard Worker    *
146*5c90c05cSAndroid Build Coastguard Worker    * **Example**:
147*5c90c05cSAndroid Build Coastguard Worker    *
148*5c90c05cSAndroid Build Coastguard Worker    *     fmt::dynamic_format_arg_store<fmt::format_context> store;
149*5c90c05cSAndroid Build Coastguard Worker    *     store.push_back(42);
150*5c90c05cSAndroid Build Coastguard Worker    *     store.push_back("abc");
151*5c90c05cSAndroid Build Coastguard Worker    *     store.push_back(1.5f);
152*5c90c05cSAndroid Build Coastguard Worker    *     std::string result = fmt::vformat("{} and {} and {}", store);
153*5c90c05cSAndroid Build Coastguard Worker    */
154*5c90c05cSAndroid Build Coastguard Worker   template <typename T> void push_back(const T& arg) {
155*5c90c05cSAndroid Build Coastguard Worker     if (detail::const_check(need_copy<T>::value))
156*5c90c05cSAndroid Build Coastguard Worker       emplace_arg(dynamic_args_.push<stored_t<T>>(arg));
157*5c90c05cSAndroid Build Coastguard Worker     else
158*5c90c05cSAndroid Build Coastguard Worker       emplace_arg(detail::unwrap(arg));
159*5c90c05cSAndroid Build Coastguard Worker   }
160*5c90c05cSAndroid Build Coastguard Worker 
161*5c90c05cSAndroid Build Coastguard Worker   /**
162*5c90c05cSAndroid Build Coastguard Worker    * Adds a reference to the argument into the dynamic store for later passing
163*5c90c05cSAndroid Build Coastguard Worker    * to a formatting function.
164*5c90c05cSAndroid Build Coastguard Worker    *
165*5c90c05cSAndroid Build Coastguard Worker    * **Example**:
166*5c90c05cSAndroid Build Coastguard Worker    *
167*5c90c05cSAndroid Build Coastguard Worker    *     fmt::dynamic_format_arg_store<fmt::format_context> store;
168*5c90c05cSAndroid Build Coastguard Worker    *     char band[] = "Rolling Stones";
169*5c90c05cSAndroid Build Coastguard Worker    *     store.push_back(std::cref(band));
170*5c90c05cSAndroid Build Coastguard Worker    *     band[9] = 'c'; // Changing str affects the output.
171*5c90c05cSAndroid Build Coastguard Worker    *     std::string result = fmt::vformat("{}", store);
172*5c90c05cSAndroid Build Coastguard Worker    *     // result == "Rolling Scones"
173*5c90c05cSAndroid Build Coastguard Worker    */
174*5c90c05cSAndroid Build Coastguard Worker   template <typename T> void push_back(std::reference_wrapper<T> arg) {
175*5c90c05cSAndroid Build Coastguard Worker     static_assert(
176*5c90c05cSAndroid Build Coastguard Worker         need_copy<T>::value,
177*5c90c05cSAndroid Build Coastguard Worker         "objects of built-in types and string views are always copied");
178*5c90c05cSAndroid Build Coastguard Worker     emplace_arg(arg.get());
179*5c90c05cSAndroid Build Coastguard Worker   }
180*5c90c05cSAndroid Build Coastguard Worker 
181*5c90c05cSAndroid Build Coastguard Worker   /**
182*5c90c05cSAndroid Build Coastguard Worker    * Adds named argument into the dynamic store for later passing to a
183*5c90c05cSAndroid Build Coastguard Worker    * formatting function. `std::reference_wrapper` is supported to avoid
184*5c90c05cSAndroid Build Coastguard Worker    * copying of the argument. The name is always copied into the store.
185*5c90c05cSAndroid Build Coastguard Worker    */
186*5c90c05cSAndroid Build Coastguard Worker   template <typename T>
187*5c90c05cSAndroid Build Coastguard Worker   void push_back(const detail::named_arg<char_type, T>& arg) {
188*5c90c05cSAndroid Build Coastguard Worker     const char_type* arg_name =
189*5c90c05cSAndroid Build Coastguard Worker         dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
190*5c90c05cSAndroid Build Coastguard Worker     if (detail::const_check(need_copy<T>::value)) {
191*5c90c05cSAndroid Build Coastguard Worker       emplace_arg(
192*5c90c05cSAndroid Build Coastguard Worker           fmt::arg(arg_name, dynamic_args_.push<stored_t<T>>(arg.value)));
193*5c90c05cSAndroid Build Coastguard Worker     } else {
194*5c90c05cSAndroid Build Coastguard Worker       emplace_arg(fmt::arg(arg_name, arg.value));
195*5c90c05cSAndroid Build Coastguard Worker     }
196*5c90c05cSAndroid Build Coastguard Worker   }
197*5c90c05cSAndroid Build Coastguard Worker 
198*5c90c05cSAndroid Build Coastguard Worker   /// Erase all elements from the store.
199*5c90c05cSAndroid Build Coastguard Worker   void clear() {
200*5c90c05cSAndroid Build Coastguard Worker     data_.clear();
201*5c90c05cSAndroid Build Coastguard Worker     named_info_.clear();
202*5c90c05cSAndroid Build Coastguard Worker     dynamic_args_ = {};
203*5c90c05cSAndroid Build Coastguard Worker   }
204*5c90c05cSAndroid Build Coastguard Worker 
205*5c90c05cSAndroid Build Coastguard Worker   /// Reserves space to store at least `new_cap` arguments including
206*5c90c05cSAndroid Build Coastguard Worker   /// `new_cap_named` named arguments.
207*5c90c05cSAndroid Build Coastguard Worker   void reserve(size_t new_cap, size_t new_cap_named) {
208*5c90c05cSAndroid Build Coastguard Worker     FMT_ASSERT(new_cap >= new_cap_named,
209*5c90c05cSAndroid Build Coastguard Worker                "set of arguments includes set of named arguments");
210*5c90c05cSAndroid Build Coastguard Worker     data_.reserve(new_cap);
211*5c90c05cSAndroid Build Coastguard Worker     named_info_.reserve(new_cap_named);
212*5c90c05cSAndroid Build Coastguard Worker   }
213*5c90c05cSAndroid Build Coastguard Worker };
214*5c90c05cSAndroid Build Coastguard Worker 
215*5c90c05cSAndroid Build Coastguard Worker FMT_END_NAMESPACE
216*5c90c05cSAndroid Build Coastguard Worker 
217*5c90c05cSAndroid Build Coastguard Worker #endif  // FMT_ARGS_H_
218