quill
args.h
1 // Formatting library for C++ - dynamic argument lists
2 //
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7 
8 #ifndef FMTQUILL_ARGS_H_
9 #define FMTQUILL_ARGS_H_
10 
11 #ifndef FMTQUILL_MODULE
12 # include <functional> // std::reference_wrapper
13 # include <memory> // std::unique_ptr
14 # include <vector>
15 #endif
16 
17 #include "format.h" // std_string_view
18 
19 FMTQUILL_BEGIN_NAMESPACE
20 namespace detail {
21 
22 template <typename T> struct is_reference_wrapper : std::false_type {};
23 template <typename T>
24 struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
25 
26 template <typename T> auto unwrap(const T& v) -> const T& { return v; }
27 template <typename T>
28 auto unwrap(const std::reference_wrapper<T>& v) -> const T& {
29  return static_cast<const T&>(v);
30 }
31 
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 };
42 
44  template <typename T> struct typed_node : node<> {
45  T value;
46 
47  template <typename Arg>
48  FMTQUILL_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
49 
50  template <typename Char>
51  FMTQUILL_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
52  : value(arg.data(), arg.size()) {}
53  };
54 
55  std::unique_ptr<node<>> head_;
56 
57  public:
58  template <typename T, typename Arg> auto push(const Arg& arg) -> const T& {
59  auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
60  auto& value = new_node->value;
61  new_node->next = std::move(head_);
62  head_ = std::move(new_node);
63  return value;
64  }
65 };
66 } // namespace detail
67 
74 template <typename Context> class dynamic_format_arg_store {
75  private:
76  using char_type = typename Context::char_type;
77 
78  template <typename T> struct need_copy {
79  static constexpr detail::type mapped_type =
81 
82  enum {
84  std::is_same<T, basic_string_view<char_type>>::value ||
85  std::is_same<T, detail::std_string_view<char_type>>::value ||
86  (mapped_type != detail::type::cstring_type &&
87  mapped_type != detail::type::string_type &&
88  mapped_type != detail::type::custom_type))
89  };
90  };
91 
92  template <typename T>
93  using stored_t = conditional_t<
94  std::is_convertible<T, std::basic_string<char_type>>::value &&
96  std::basic_string<char_type>, T>;
97 
98  // Storage of basic_format_arg must be contiguous.
99  std::vector<basic_format_arg<Context>> data_;
100  std::vector<detail::named_arg_info<char_type>> named_info_;
101 
102  // Storage of arguments not fitting into basic_format_arg must grow
103  // without relocation because items in data_ refer to it.
104  detail::dynamic_arg_list dynamic_args_;
105 
106  friend class basic_format_args<Context>;
107 
108  auto data() const -> const basic_format_arg<Context>* {
109  return named_info_.empty() ? data_.data() : data_.data() + 1;
110  }
111 
112  template <typename T> void emplace_arg(const T& arg) {
113  data_.emplace_back(arg);
114  }
115 
116  template <typename T>
117  void emplace_arg(const detail::named_arg<char_type, T>& arg) {
118  if (named_info_.empty())
119  data_.insert(data_.begin(), basic_format_arg<Context>(nullptr, 0));
120  data_.emplace_back(detail::unwrap(arg.value));
121  auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
122  data->pop_back();
123  };
124  std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
125  guard{&data_, pop_one};
126  named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
127  data_[0] = {named_info_.data(), named_info_.size()};
128  guard.release();
129  }
130 
131  public:
132  constexpr dynamic_format_arg_store() = default;
133 
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 
154  template <typename T> void push_back(const T& arg) {
155  if (detail::const_check(need_copy<T>::value))
156  emplace_arg(dynamic_args_.push<stored_t<T>>(arg));
157  else
158  emplace_arg(detail::unwrap(arg));
159  }
160 
174  template <typename T> void push_back(std::reference_wrapper<T> arg) {
175  static_assert(
176  need_copy<T>::value,
177  "objects of built-in types and string views are always copied");
178  emplace_arg(arg.get());
179  }
180 
186  template <typename T>
188  const char_type* arg_name =
189  dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
190  if (detail::const_check(need_copy<T>::value)) {
191  emplace_arg(
192  fmtquill::arg(arg_name, dynamic_args_.push<stored_t<T>>(arg.value)));
193  } else {
194  emplace_arg(fmtquill::arg(arg_name, arg.value));
195  }
196  }
197 
199  void clear() {
200  data_.clear();
201  named_info_.clear();
202  dynamic_args_ = {};
203  }
204 
207  void reserve(size_t new_cap, size_t new_cap_named) {
208  FMTQUILL_ASSERT(new_cap >= new_cap_named,
209  "set of arguments includes set of named arguments");
210  data_.reserve(new_cap);
211  named_info_.reserve(new_cap_named);
212  }
213 
215  size_t size() const noexcept { return data_.size(); }
216 };
217 
218 FMTQUILL_END_NAMESPACE
219 
220 #endif // FMTQUILL_ARGS_H_
void push_back(const T &arg)
Adds an argument into the dynamic store for later passing to a formatting function.
Definition: args.h:154
Definition: base.h:1044
Definition: args.h:38
Definition: base.h:988
Definition: format.h:126
constexpr auto data() const noexcept -> const Char *
Returns a pointer to the string data.
Definition: base.h:565
A dynamic list of formatting arguments with storage.
Definition: args.h:74
constexpr auto size() const noexcept -> size_t
Returns the string size.
Definition: base.h:568
void push_back(std::reference_wrapper< T > arg)
Adds a reference to the argument into the dynamic store for later passing to a formatting function...
Definition: args.h:174
Definition: args.h:22
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:24
An implementation of std::basic_string_view for pre-C++17.
Definition: base.h:523
A view of a collection of formatting arguments.
Definition: base.h:661
Definition: args.h:43
Definition: base.h:2147
Definition: base.h:660
size_t size() const noexcept
Returns the number of elements in the store.
Definition: args.h:215
void push_back(const detail::named_arg< char_type, T > &arg)
Adds named argument into the dynamic store for later passing to a formatting function.
Definition: args.h:187
void reserve(size_t new_cap, size_t new_cap_named)
Reserves space to store at least new_cap arguments including new_cap_named named arguments.
Definition: args.h:207
void clear()
Erase all elements from the store.
Definition: args.h:199