Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:57:19

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