OR-Tools  9.1
container_logging.h
Go to the documentation of this file.
1 // Copyright 2010-2021 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 // Utilities for container logging.
15 // TODO(user): Broaden the scope and rename to "stream_util.h"
16 //
17 //
18 // The typical use looks like this:
19 //
20 // LOG(INFO) << gtl::LogContainer(container);
21 //
22 // By default, LogContainer() uses the LogShortUpTo100 policy: comma-space
23 // separation, no newlines, and with limit of 100 items.
24 //
25 // Policies can be specified:
26 //
27 // LOG(INFO) << gtl::LogContainer(container, gtl::LogMultiline());
28 //
29 // The above example will print the container using newlines between
30 // elements, enclosed in [] braces.
31 //
32 // See below for further details on policies.
33 
34 #ifndef OR_TOOLS_BASE_CONTAINER_LOGGING_H_
35 #define OR_TOOLS_BASE_CONTAINER_LOGGING_H_
36 
37 #include <limits>
38 #include <ostream>
39 #include <sstream>
40 #include <string>
41 #include <type_traits>
42 
44 
45 namespace gtl {
46 
47 // Several policy classes below determine how LogRangeToStream will
48 // format a range of items. A Policy class should have these methods:
49 //
50 // Called to print an individual container element.
51 // void Log(ostream &out, const ElementT &element) const;
52 //
53 // Called before printing the set of elements:
54 // void LogOpening(ostream &out) const;
55 //
56 // Called after printing the set of elements:
57 // void LogClosing(ostream &out) const;
58 //
59 // Called before printing the first element:
60 // void LogFirstSeparator(ostream &out) const;
61 //
62 // Called before printing the remaining elements:
63 // void LogSeparator(ostream &out) const;
64 //
65 // Returns the maximum number of elements to print:
66 // int64_t MaxElements() const;
67 //
68 // Called to print an indication that MaximumElements() was reached:
69 // void LogEllipsis(ostream &out) const;
70 
71 namespace internal {
72 
73 struct LogBase {
74  template <typename ElementT>
75  void Log(std::ostream& out, const ElementT& element) const { // NOLINT
76  out << element;
77  }
78  void LogEllipsis(std::ostream& out) const { // NOLINT
79  out << "...";
80  }
81 };
82 
83 struct LogShortBase : public LogBase {
84  void LogOpening(std::ostream& out) const { out << "["; } // NOLINT
85  void LogClosing(std::ostream& out) const { out << "]"; } // NOLINT
86  void LogFirstSeparator(std::ostream& out) const { out << ""; } // NOLINT
87  void LogSeparator(std::ostream& out) const { out << ", "; } // NOLINT
88 };
89 
90 struct LogMultilineBase : public LogBase {
91  void LogOpening(std::ostream& out) const { out << "["; } // NOLINT
92  void LogClosing(std::ostream& out) const { out << "\n]"; } // NOLINT
93  void LogFirstSeparator(std::ostream& out) const { out << "\n"; } // NOLINT
94  void LogSeparator(std::ostream& out) const { out << "\n"; } // NOLINT
95 };
96 
97 struct LogLegacyBase : public LogBase {
98  void LogOpening(std::ostream& out) const { out << ""; } // NOLINT
99  void LogClosing(std::ostream& out) const { out << ""; } // NOLINT
100  void LogFirstSeparator(std::ostream& out) const { out << ""; } // NOLINT
101  void LogSeparator(std::ostream& out) const { out << " "; } // NOLINT
102 };
103 
104 } // namespace internal
105 
106 // LogShort uses [] braces and separates items with comma-spaces. For
107 // example "[1, 2, 3]".
109  int64_t MaxElements() const { return std::numeric_limits<int64_t>::max(); }
110 };
111 
112 // LogShortUpToN(max_elements) formats the same as LogShort but prints no more
113 // than the max_elements elements.
115  public:
116  explicit LogShortUpToN(int64_t max_elements) : max_elements_(max_elements) {}
117  int64_t MaxElements() const { return max_elements_; }
118 
119  private:
120  int64_t max_elements_;
121 };
122 
123 // LogShortUpTo100 formats the same as LogShort but prints no more
124 // than 100 elements.
127 };
128 
129 // LogMultiline uses [] braces and separates items with
130 // newlines. For example "[
131 // 1
132 // 2
133 // 3
134 // ]".
136  int64_t MaxElements() const { return std::numeric_limits<int64_t>::max(); }
137 };
138 
139 // LogMultilineUpToN(max_elements) formats the same as LogMultiline but
140 // prints no more than max_elements elements.
142  public:
143  explicit LogMultilineUpToN(int64_t max_elements)
144  : max_elements_(max_elements) {}
145  int64_t MaxElements() const { return max_elements_; }
146 
147  private:
148  int64_t max_elements_;
149 };
150 
151 // LogMultilineUpTo100 formats the same as LogMultiline but
152 // prints no more than 100 elements.
155 };
156 
157 // The legacy behavior of LogSequence() does not use braces and
158 // separates items with spaces. For example "1 2 3".
160  int64_t MaxElements() const { return 100; }
161 };
163  int64_t MaxElements() const { return std::numeric_limits<int64_t>::max(); }
164 };
165 
166 // The default policy for new code.
168 
169 // LogRangeToStream should be used to define operator<< for
170 // STL and STL-like containers. For example, see stl_logging.h.
171 template <typename IteratorT, typename PolicyT>
172 inline void LogRangeToStream(std::ostream& out, // NOLINT
173  IteratorT begin, IteratorT end,
174  const PolicyT& policy) {
175  policy.LogOpening(out);
176  for (int64_t i = 0; begin != end && i < policy.MaxElements(); ++i, ++begin) {
177  if (i == 0) {
178  policy.LogFirstSeparator(out);
179  } else {
180  policy.LogSeparator(out);
181  }
182  policy.Log(out, *begin);
183  }
184  if (begin != end) {
185  policy.LogSeparator(out);
186  policy.LogEllipsis(out);
187  }
188  policy.LogClosing(out);
189 }
190 
191 namespace detail {
192 
193 // RangeLogger is a helper class for gtl::LogRange and
194 // gtl::LogContainer; do not use it directly. This object
195 // captures iterators into the argument of the LogRange and
196 // LogContainer functions, so its lifetime should be confined to a
197 // single logging statement. Objects of this type should not be
198 // assigned to local variables.
199 template <typename IteratorT, typename PolicyT>
200 class RangeLogger {
201  public:
202  RangeLogger(const IteratorT& begin, const IteratorT& end,
203  const PolicyT& policy)
204  : begin_(begin), end_(end), policy_(policy) {}
205 
206  friend std::ostream& operator<<(std::ostream& out, const RangeLogger& range) {
207  gtl::LogRangeToStream<IteratorT, PolicyT>(out, range.begin_, range.end_,
208  range.policy_);
209  return out;
210  }
211 
212  // operator<< above is generally recommended. However, some situations may
213  // require a string, so a convenience str() method is provided as well.
214  std::string str() const {
215  std::stringstream ss;
216  ss << *this;
217  return ss.str();
218  }
219 
220  private:
221  IteratorT begin_;
222  IteratorT end_;
223  PolicyT policy_;
224 };
225 
226 template <typename E>
227 class EnumLogger {
228  public:
229  explicit EnumLogger(E e) : e_(e) {}
230 
231  friend std::ostream& operator<<(std::ostream& out, const EnumLogger& v) {
232  using I = typename std::underlying_type<E>::type;
233  return out << static_cast<I>(v.e_);
234  }
235 
236  private:
237  E e_;
238 };
239 
240 } // namespace detail
241 
242 // Log a range using "policy". For example:
243 //
244 // LOG(INFO) << gtl::LogRange(start_pos, end_pos, gtl::LogMultiline());
245 //
246 // The above example will print the range using newlines between
247 // elements, enclosed in [] braces.
248 template <typename IteratorT, typename PolicyT>
250  const IteratorT& end,
251  const PolicyT& policy) {
252  return gtl::detail::RangeLogger<IteratorT, PolicyT>(begin, end, policy);
253 }
254 
255 // Log a range. For example:
256 //
257 // LOG(INFO) << gtl::LogRange(start_pos, end_pos);
258 //
259 // By default, Range() uses the LogShortUpTo100 policy: comma-space
260 // separation, no newlines, and with limit of 100 items.
261 template <typename IteratorT>
263  const IteratorT& end) {
264  return gtl::LogRange(begin, end, LogDefault());
265 }
266 
267 // Log a container using "policy". For example:
268 //
269 // LOG(INFO) << gtl::LogContainer(container, gtl::LogMultiline());
270 //
271 // The above example will print the container using newlines between
272 // elements, enclosed in [] braces.
273 template <typename ContainerT, typename PolicyT>
274 auto LogContainer(const ContainerT& container, const PolicyT& policy)
275  -> decltype(gtl::LogRange(container.begin(), container.end(), policy)) {
276  return gtl::LogRange(container.begin(), container.end(), policy);
277 }
278 
279 // Log a container. For example:
280 //
281 // LOG(INFO) << gtl::LogContainer(container);
282 //
283 // By default, Container() uses the LogShortUpTo100 policy: comma-space
284 // separation, no newlines, and with limit of 100 items.
285 template <typename ContainerT>
286 auto LogContainer(const ContainerT& container)
287  -> decltype(gtl::LogContainer(container, LogDefault())) {
288  return gtl::LogContainer(container, LogDefault());
289 }
290 
291 // Log a (possibly scoped) enum. For example:
292 //
293 // enum class Color { kRed, kGreen, kBlue };
294 // LOG(INFO) << gtl::LogEnum(kRed);
295 template <typename E>
297  static_assert(std::is_enum<E>::value, "must be an enum");
298  return detail::EnumLogger<E>(e);
299 }
300 
301 } // namespace gtl
302 
303 #endif // OR_TOOLS_BASE_CONTAINER_LOGGING_H_
void LogOpening(std::ostream &out) const
RangeLogger(const IteratorT &begin, const IteratorT &end, const PolicyT &policy)
LogMultilineUpToN(int64_t max_elements)
LogShortUpTo100 LogDefault
void LogRangeToStream(std::ostream &out, IteratorT begin, IteratorT end, const PolicyT &policy)
int64_t max
Definition: alldiff_cst.cc:140
int64_t MaxElements() const
void LogClosing(std::ostream &out) const
void LogSeparator(std::ostream &out) const
friend std::ostream & operator<<(std::ostream &out, const EnumLogger &v)
int64_t MaxElements() const
void LogFirstSeparator(std::ostream &out) const
void LogOpening(std::ostream &out) const
void LogClosing(std::ostream &out) const
friend std::ostream & operator<<(std::ostream &out, const RangeLogger &range)
void LogFirstSeparator(std::ostream &out) const
auto LogContainer(const ContainerT &container, const PolicyT &policy) -> decltype(gtl::LogRange(container.begin(), container.end(), policy))
void LogSeparator(std::ostream &out) const
void LogFirstSeparator(std::ostream &out) const
void LogEllipsis(std::ostream &out) const
void Log(std::ostream &out, const ElementT &element) const
LogShortUpToN(int64_t max_elements)
int64_t MaxElements() const
int64_t MaxElements() const
void LogSeparator(std::ostream &out) const
void LogClosing(std::ostream &out) const
detail::EnumLogger< E > LogEnum(E e)
detail::RangeLogger< IteratorT, PolicyT > LogRange(const IteratorT &begin, const IteratorT &end, const PolicyT &policy)
void LogOpening(std::ostream &out) const
int64_t value
int64_t MaxElements() const
std::string str() const
int64_t MaxElements() const