Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-05 08:54:14

0001 // Formatting library for C++ - dynamic argument lists
0002 //
0003 // Copyright (c) 2012 - present, Victor Zverovich
0004 // All rights reserved.
0005 //
0006 // For the license information refer to format.h.
0007 
0008 #ifndef FMT_ARGS_H_
0009 #define FMT_ARGS_H_
0010 
0011 #include <functional>  // std::reference_wrapper
0012 #include <memory>      // std::unique_ptr
0013 #include <vector>
0014 
0015 #include "core.h"
0016 
0017 FMT_BEGIN_NAMESPACE
0018 
0019 namespace detail {
0020 
0021 template <typename T> struct is_reference_wrapper : std::false_type {};
0022 template <typename T>
0023 struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
0024 
0025 template <typename T> auto unwrap(const T& v) -> const T& { return v; }
0026 template <typename T>
0027 auto unwrap(const std::reference_wrapper<T>& v) -> const T& {
0028   return static_cast<const T&>(v);
0029 }
0030 
0031 class dynamic_arg_list {
0032   // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
0033   // templates it doesn't complain about inability to deduce single translation
0034   // unit for placing vtable. So storage_node_base is made a fake template.
0035   template <typename = void> struct node {
0036     virtual ~node() = default;
0037     std::unique_ptr<node<>> next;
0038   };
0039 
0040   template <typename T> struct typed_node : node<> {
0041     T value;
0042 
0043     template <typename Arg>
0044     FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
0045 
0046     template <typename Char>
0047     FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
0048         : value(arg.data(), arg.size()) {}
0049   };
0050 
0051   std::unique_ptr<node<>> head_;
0052 
0053  public:
0054   template <typename T, typename Arg> auto push(const Arg& arg) -> const T& {
0055     auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
0056     auto& value = new_node->value;
0057     new_node->next = std::move(head_);
0058     head_ = std::move(new_node);
0059     return value;
0060   }
0061 };
0062 }  // namespace detail
0063 
0064 /**
0065   \rst
0066   A dynamic version of `fmt::format_arg_store`.
0067   It's equipped with a storage to potentially temporary objects which lifetimes
0068   could be shorter than the format arguments object.
0069 
0070   It can be implicitly converted into `~fmt::basic_format_args` for passing
0071   into type-erased formatting functions such as `~fmt::vformat`.
0072   \endrst
0073  */
0074 template <typename Context>
0075 class dynamic_format_arg_store
0076 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
0077     // Workaround a GCC template argument substitution bug.
0078     : public basic_format_args<Context>
0079 #endif
0080 {
0081  private:
0082   using char_type = typename Context::char_type;
0083 
0084   template <typename T> struct need_copy {
0085     static constexpr detail::type mapped_type =
0086         detail::mapped_type_constant<T, Context>::value;
0087 
0088     enum {
0089       value = !(detail::is_reference_wrapper<T>::value ||
0090                 std::is_same<T, basic_string_view<char_type>>::value ||
0091                 std::is_same<T, detail::std_string_view<char_type>>::value ||
0092                 (mapped_type != detail::type::cstring_type &&
0093                  mapped_type != detail::type::string_type &&
0094                  mapped_type != detail::type::custom_type))
0095     };
0096   };
0097 
0098   template <typename T>
0099   using stored_type = conditional_t<
0100       std::is_convertible<T, std::basic_string<char_type>>::value &&
0101           !detail::is_reference_wrapper<T>::value,
0102       std::basic_string<char_type>, T>;
0103 
0104   // Storage of basic_format_arg must be contiguous.
0105   std::vector<basic_format_arg<Context>> data_;
0106   std::vector<detail::named_arg_info<char_type>> named_info_;
0107 
0108   // Storage of arguments not fitting into basic_format_arg must grow
0109   // without relocation because items in data_ refer to it.
0110   detail::dynamic_arg_list dynamic_args_;
0111 
0112   friend class basic_format_args<Context>;
0113 
0114   auto get_types() const -> unsigned long long {
0115     return detail::is_unpacked_bit | data_.size() |
0116            (named_info_.empty()
0117                 ? 0ULL
0118                 : static_cast<unsigned long long>(detail::has_named_args_bit));
0119   }
0120 
0121   auto data() const -> const basic_format_arg<Context>* {
0122     return named_info_.empty() ? data_.data() : data_.data() + 1;
0123   }
0124 
0125   template <typename T> void emplace_arg(const T& arg) {
0126     data_.emplace_back(detail::make_arg<Context>(arg));
0127   }
0128 
0129   template <typename T>
0130   void emplace_arg(const detail::named_arg<char_type, T>& arg) {
0131     if (named_info_.empty()) {
0132       constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr};
0133       data_.insert(data_.begin(), {zero_ptr, 0});
0134     }
0135     data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value)));
0136     auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
0137       data->pop_back();
0138     };
0139     std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
0140         guard{&data_, pop_one};
0141     named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
0142     data_[0].value_.named_args = {named_info_.data(), named_info_.size()};
0143     guard.release();
0144   }
0145 
0146  public:
0147   constexpr dynamic_format_arg_store() = default;
0148 
0149   /**
0150     \rst
0151     Adds an argument into the dynamic store for later passing to a formatting
0152     function.
0153 
0154     Note that custom types and string types (but not string views) are copied
0155     into the store dynamically allocating memory if necessary.
0156 
0157     **Example**::
0158 
0159       fmt::dynamic_format_arg_store<fmt::format_context> store;
0160       store.push_back(42);
0161       store.push_back("abc");
0162       store.push_back(1.5f);
0163       std::string result = fmt::vformat("{} and {} and {}", store);
0164     \endrst
0165   */
0166   template <typename T> void push_back(const T& arg) {
0167     if (detail::const_check(need_copy<T>::value))
0168       emplace_arg(dynamic_args_.push<stored_type<T>>(arg));
0169     else
0170       emplace_arg(detail::unwrap(arg));
0171   }
0172 
0173   /**
0174     \rst
0175     Adds a reference to the argument into the dynamic store for later passing to
0176     a formatting function.
0177 
0178     **Example**::
0179 
0180       fmt::dynamic_format_arg_store<fmt::format_context> store;
0181       char band[] = "Rolling Stones";
0182       store.push_back(std::cref(band));
0183       band[9] = 'c'; // Changing str affects the output.
0184       std::string result = fmt::vformat("{}", store);
0185       // result == "Rolling Scones"
0186     \endrst
0187   */
0188   template <typename T> void push_back(std::reference_wrapper<T> arg) {
0189     static_assert(
0190         need_copy<T>::value,
0191         "objects of built-in types and string views are always copied");
0192     emplace_arg(arg.get());
0193   }
0194 
0195   /**
0196     Adds named argument into the dynamic store for later passing to a formatting
0197     function. ``std::reference_wrapper`` is supported to avoid copying of the
0198     argument. The name is always copied into the store.
0199   */
0200   template <typename T>
0201   void push_back(const detail::named_arg<char_type, T>& arg) {
0202     const char_type* arg_name =
0203         dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
0204     if (detail::const_check(need_copy<T>::value)) {
0205       emplace_arg(
0206           fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value)));
0207     } else {
0208       emplace_arg(fmt::arg(arg_name, arg.value));
0209     }
0210   }
0211 
0212   /** Erase all elements from the store */
0213   void clear() {
0214     data_.clear();
0215     named_info_.clear();
0216     dynamic_args_ = detail::dynamic_arg_list();
0217   }
0218 
0219   /**
0220     \rst
0221     Reserves space to store at least *new_cap* arguments including
0222     *new_cap_named* named arguments.
0223     \endrst
0224   */
0225   void reserve(size_t new_cap, size_t new_cap_named) {
0226     FMT_ASSERT(new_cap >= new_cap_named,
0227                "Set of arguments includes set of named arguments");
0228     data_.reserve(new_cap);
0229     named_info_.reserve(new_cap_named);
0230   }
0231 };
0232 
0233 FMT_END_NAMESPACE
0234 
0235 #endif  // FMT_ARGS_H_