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