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