Google OR-Tools v9.14
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
dump_vars.h
Go to the documentation of this file.
1// Copyright 2010-2025 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14// DUMP_VARS() is a convenience macro for writing objects to text logs. It
15// prints all of its arguments as key-value pairs.
16//
17// Example:
18// int foo = 42;
19// vector<int> bar = {1, 2, 3};
20// // Prints: foo = 42, bar.size() = 3
21// LOG(INFO) << DUMP_VARS(foo, bar.size());
22//
23// DUMP_VARS() produces high quality human-readable output for most types:
24// builtin types, strings, anything with operator<<.
25//
26// ====[ Limitations ]====
27//
28// DUMP_VARS() accepts at most 8 arguments.
29//
30// Structured bindings require an extra step to make DUMP_VARS print them. They
31// need to be listed as first argument of DUMP_VARS_WITH_BINDINGS:
32//
33// for (const auto& [x, y, z] : Foo()) {
34// // Would not compile:
35// // LOG(INFO) << DUMP_VARS(x, *y, f(z), other_var);
36// LOG(INFO) << DUMP_VARS_WITH_BINDINGS((x, y, z), x, *y, f(z), other_var);
37// }
38
39#ifndef OR_TOOLS_BASE_DUMP_VARS_H_
40#define OR_TOOLS_BASE_DUMP_VARS_H_
41
42#include <optional>
43#include <ostream>
44#include <sstream>
45#include <string>
46#include <utility>
47#include <vector>
48
49#include "absl/container/inlined_vector.h"
51
52/* need extra level to force extra eval */
53#define DUMP_FOR_EACH_N0(F)
54#define DUMP_FOR_EACH_N1(F, a) F(a)
55#define DUMP_FOR_EACH_N2(F, a, ...) F(a) DUMP_FOR_EACH_N1(F, __VA_ARGS__)
56#define DUMP_FOR_EACH_N3(F, a, ...) F(a) DUMP_FOR_EACH_N2(F, __VA_ARGS__)
57#define DUMP_FOR_EACH_N4(F, a, ...) F(a) DUMP_FOR_EACH_N3(F, __VA_ARGS__)
58#define DUMP_FOR_EACH_N5(F, a, ...) F(a) DUMP_FOR_EACH_N4(F, __VA_ARGS__)
59#define DUMP_FOR_EACH_N6(F, a, ...) F(a) DUMP_FOR_EACH_N5(F, __VA_ARGS__)
60#define DUMP_FOR_EACH_N7(F, a, ...) F(a) DUMP_FOR_EACH_N6(F, __VA_ARGS__)
61#define DUMP_FOR_EACH_N8(F, a, ...) F(a) DUMP_FOR_EACH_N7(F, __VA_ARGS__)
62#define DUMP_FOR_EACH_N9(F, a, ...) F(a) DUMP_FOR_EACH_N8(F, __VA_ARGS__)
63#define DUMP_FOR_EACH_N10(F, a, ...) F(a) DUMP_FOR_EACH_N9(F, __VA_ARGS__)
64#define DUMP_FOR_EACH_N11(F, a, ...) F(a) DUMP_FOR_EACH_N10(F, __VA_ARGS__)
65#define DUMP_FOR_EACH_N12(F, a, ...) F(a) DUMP_FOR_EACH_N11(F, __VA_ARGS__)
66
67#define DUMP_CONCATENATE(x, y) x##y
68#define DUMP_FOR_EACH_(N, F, ...) \
69 DUMP_CONCATENATE(DUMP_FOR_EACH_N, N)(F __VA_OPT__(, __VA_ARGS__))
70
71#define DUMP_NARG(...) DUMP_NARG_(__VA_OPT__(__VA_ARGS__, ) DUMP_RSEQ_N())
72#define DUMP_NARG_(...) DUMP_ARG_N(__VA_ARGS__)
73#define DUMP_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N, ...) N
74#define DUMP_RSEQ_N() 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
75#define DUMP_FOR_EACH(F, ...) \
76 DUMP_FOR_EACH_(DUMP_NARG(__VA_ARGS__), F __VA_OPT__(, __VA_ARGS__))
77
78#define DUMP_VARS(...) DUMP_VARS_WITH_BINDINGS((), __VA_ARGS__)
79
80/* need extra level to force extra eval */
81#define DUMP_STRINGIZE(a) #a,
82#define DUMP_STRINGIFY(...) DUMP_FOR_EACH(DUMP_STRINGIZE, __VA_ARGS__)
83
84// Returns the arguments.
85#define DUMP_IDENTITY(...) __VA_ARGS__
86// Removes parenthesis. Requires argument enclosed in parenthesis.
87#define DUMP_RM_PARENS(...) DUMP_IDENTITY __VA_ARGS__
88
89#define DUMP_GEN_ONE_BINDING(a) , &a = a
90#define DUMP_GEN_BINDING(binding) \
91 &DUMP_FOR_EACH(DUMP_GEN_ONE_BINDING, DUMP_RM_PARENS(binding))
92
93#define DUMP_VARS_WITH_BINDINGS(binding, ...) \
94 ::operations_research::base::internal_dump_vars::make_dump_vars<>( \
95 ::operations_research::base::internal_dump_vars::DumpNames{ \
96 DUMP_STRINGIFY(__VA_ARGS__)}, \
97 [DUMP_GEN_BINDING(binding)]( \
98 ::std::ostream& os, const ::std::string& field_sep, \
99 const ::std::string& kv_sep, \
100 const ::operations_research::base::internal_dump_vars::DumpNames& \
101 names) { \
102 ::operations_research::base::internal_dump_vars::print_fields{ \
103 .os = os, \
104 .field_sep = field_sep, \
105 .kv_sep = kv_sep, \
106 .names = names, \
107 }(__VA_ARGS__); \
108 })
109
112
113// needed by routing
114template <typename T>
115std::ostream& operator<<(std::ostream& os,
116 const ::absl::InlinedVector<T, 8>& vec) {
117 for (T it : vec) {
118 os << ::std::to_string(it) << ',';
119 }
120 return os;
121}
122
123// needed by algorithms tests
124template <typename T>
125std::ostream& operator<<(std::ostream& os, const ::std::vector<T>& vec) {
126 for (T it : vec) {
127 os << ::std::to_string(it) << ',';
128 }
129 return os;
130}
131
132template <typename T>
133std::ostream& operator<<(std::ostream& os, const ::std::optional<T>& opt) {
134 if (opt.has_value())
135 os << ::std::to_string(opt.value());
136 else
137 os << "(none)";
138 return os;
139}
140
141// needed by graph tests
142template <typename T, typename U>
143std::ostream& operator<<(std::ostream& os,
144 const ::util_intops::StrongVector<T, U>& vec) {
145 for (U it : vec) {
146 os << ::std::to_string(it) << ',';
147 }
148 return os;
149}
150
151using DumpNames = ::std::vector<::std::string>;
152
154 void operator()() {}
155
156 template <class T>
157 void operator()(const T& t) {
158 os << names[n++] << kv_sep << t;
159 }
160
161 template <class T1, class T2, class... Ts>
162 void operator()(const T1& t1, const T2& t2, const Ts&... ts) {
163 os << names[n++] << kv_sep << t1 << field_sep;
164 (*this)(t2, ts...);
165 }
166
167 std::ostream& os;
168 const ::std::string& field_sep;
169 const ::std::string& kv_sep;
171 ::std::size_t n = 0;
172};
173
174template <class F>
175class Dump {
176 public:
177 explicit Dump(const ::std::string&& field_sep, const ::std::string&& kv_sep,
178 DumpNames&& names, F f)
179 : field_sep_(::std::move(field_sep)),
180 kv_sep_(::std::move(kv_sep)),
181 names_(::std::move(names)),
182 f_(::std::move(f)) {}
183
184 ::std::string str() const {
185 ::std::ostringstream oss;
186 oss << *this;
187 return oss.str();
188 }
189
190 template <class... N>
191 Dump<F> as(N&&... names) const {
192 return Dump<F>(::std::string{field_sep_}, ::std::string{kv_sep_},
193 DumpNames{names...}, f_);
194 }
195
196 Dump& sep(::std::string&& field_sep) {
197 field_sep_ = ::std::move(field_sep);
198 return *this;
199 }
200
201 Dump& sep(::std::string&& field_sep, ::std::string&& kv_sep) {
202 field_sep_ = ::std::move(field_sep);
203 kv_sep_ = ::std::move(kv_sep);
204 return *this;
205 }
206
207 friend ::std::ostream& operator<<(::std::ostream& os, const Dump& dump) {
208 dump.print_fields_(os);
209 return os;
210 }
211
212 private:
213 void print_fields_(::std::ostream& os) const {
214 f_(os, field_sep_, kv_sep_, names_);
215 }
216
217 ::std::string field_sep_;
218 ::std::string kv_sep_;
219 DumpNames names_;
220 F f_;
221};
222
223template <class F>
225 return Dump<F>(
226 /*field_sep=*/", ",
227 /*kv_sep=*/" = ", ::std::move(names), ::std::move(f));
228}
229
230} // namespace internal_dump_vars
231} // namespace operations_research::base
232
233#endif // OR_TOOLS_BASE_DUMP_VARS_H_
friend::std::ostream & operator<<(::std::ostream &os, const Dump &dump)
Definition dump_vars.h:207
Dump & sep(::std::string &&field_sep, ::std::string &&kv_sep)
Definition dump_vars.h:201
Dump & sep(::std::string &&field_sep)
Definition dump_vars.h:196
Dump(const ::std::string &&field_sep, const ::std::string &&kv_sep, DumpNames &&names, F f)
Definition dump_vars.h:177
Dump< F > make_dump_vars(DumpNames &&names, F f)
Definition dump_vars.h:224
std::ostream & operator<<(std::ostream &os, const ::absl::InlinedVector< T, 8 > &vec)
needed by routing
Definition dump_vars.h:115
::std::vector<::std::string > DumpNames
Definition dump_vars.h:151
STL namespace.
void operator()(const T1 &t1, const T2 &t2, const Ts &... ts)
Definition dump_vars.h:162