mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 20:14:23 +08:00
313 lines
10 KiB
C++
313 lines
10 KiB
C++
// Copyright 2025 The Abseil Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
// The typical use looks like this:
|
|
//
|
|
// LOG(INFO) << LogContainer(container);
|
|
//
|
|
// By default, LogContainer() uses the LogShortUpTo100 policy: comma-space
|
|
// separation, no newlines, and with limit of 100 items.
|
|
//
|
|
// Policies can be specified:
|
|
//
|
|
// LOG(INFO) << LogContainer(container, LogMultiline());
|
|
//
|
|
// The above example will print the container using newlines between elements,
|
|
// enclosed in [] braces.
|
|
//
|
|
// See below for further details on policies.
|
|
|
|
#ifndef ABSL_LOG_INTERNAL_CONTAINER_H_
|
|
#define ABSL_LOG_INTERNAL_CONTAINER_H_
|
|
|
|
#include <cstdint>
|
|
#include <limits>
|
|
#include <ostream>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <type_traits>
|
|
|
|
#include "absl/base/config.h"
|
|
#include "absl/meta/internal/requires.h"
|
|
#include "absl/strings/str_cat.h"
|
|
|
|
namespace absl {
|
|
ABSL_NAMESPACE_BEGIN
|
|
namespace log_internal {
|
|
|
|
// Several policy classes below determine how LogRangeToStream will
|
|
// format a range of items. A Policy class should have these methods:
|
|
//
|
|
// Called to print an individual container element.
|
|
// void Log(ostream &out, const ElementT &element) const;
|
|
//
|
|
// Called before printing the set of elements:
|
|
// void LogOpening(ostream &out) const;
|
|
//
|
|
// Called after printing the set of elements:
|
|
// void LogClosing(ostream &out) const;
|
|
//
|
|
// Called before printing the first element:
|
|
// void LogFirstSeparator(ostream &out) const;
|
|
//
|
|
// Called before printing the remaining elements:
|
|
// void LogSeparator(ostream &out) const;
|
|
//
|
|
// Returns the maximum number of elements to print:
|
|
// int64 MaxElements() const;
|
|
//
|
|
// Called to print an indication that MaximumElements() was reached:
|
|
// void LogEllipsis(ostream &out) const;
|
|
|
|
namespace internal {
|
|
|
|
struct LogBase {
|
|
template <typename ElementT>
|
|
void Log(std::ostream &out, const ElementT &element) const { // NOLINT
|
|
// Fallback to `AbslStringify` if the type does not have `operator<<`.
|
|
if constexpr (meta_internal::Requires<std::ostream, ElementT>(
|
|
[](auto&& x, auto&& y) -> decltype(x << y) {})) {
|
|
out << element;
|
|
} else {
|
|
out << absl::StrCat(element);
|
|
}
|
|
}
|
|
void LogEllipsis(std::ostream &out) const { // NOLINT
|
|
out << "...";
|
|
}
|
|
};
|
|
|
|
struct LogShortBase : public LogBase {
|
|
void LogOpening(std::ostream &out) const { out << "["; } // NOLINT
|
|
void LogClosing(std::ostream &out) const { out << "]"; } // NOLINT
|
|
void LogFirstSeparator(std::ostream &out) const { out << ""; } // NOLINT
|
|
void LogSeparator(std::ostream &out) const { out << ", "; } // NOLINT
|
|
};
|
|
|
|
struct LogMultilineBase : public LogBase {
|
|
void LogOpening(std::ostream &out) const { out << "["; } // NOLINT
|
|
void LogClosing(std::ostream &out) const { out << "\n]"; } // NOLINT
|
|
void LogFirstSeparator(std::ostream &out) const { out << "\n"; } // NOLINT
|
|
void LogSeparator(std::ostream &out) const { out << "\n"; } // NOLINT
|
|
};
|
|
|
|
struct LogLegacyBase : public LogBase {
|
|
void LogOpening(std::ostream &out) const { out << ""; } // NOLINT
|
|
void LogClosing(std::ostream &out) const { out << ""; } // NOLINT
|
|
void LogFirstSeparator(std::ostream &out) const { out << ""; } // NOLINT
|
|
void LogSeparator(std::ostream &out) const { out << " "; } // NOLINT
|
|
};
|
|
|
|
} // namespace internal
|
|
|
|
// LogShort uses [] braces and separates items with comma-spaces. For
|
|
// example "[1, 2, 3]".
|
|
struct LogShort : public internal::LogShortBase {
|
|
int64_t MaxElements() const { return (std::numeric_limits<int64_t>::max)(); }
|
|
};
|
|
|
|
// LogShortUpToN(max_elements) formats the same as LogShort but prints no more
|
|
// than the max_elements elements.
|
|
class LogShortUpToN : public internal::LogShortBase {
|
|
public:
|
|
explicit LogShortUpToN(int64_t max_elements) : max_elements_(max_elements) {}
|
|
int64_t MaxElements() const { return max_elements_; }
|
|
|
|
private:
|
|
int64_t max_elements_;
|
|
};
|
|
|
|
// LogShortUpTo100 formats the same as LogShort but prints no more
|
|
// than 100 elements.
|
|
struct LogShortUpTo100 : public LogShortUpToN {
|
|
LogShortUpTo100() : LogShortUpToN(100) {}
|
|
};
|
|
|
|
// LogMultiline uses [] braces and separates items with
|
|
// newlines. For example "[
|
|
// 1
|
|
// 2
|
|
// 3
|
|
// ]".
|
|
struct LogMultiline : public internal::LogMultilineBase {
|
|
int64_t MaxElements() const { return (std::numeric_limits<int64_t>::max)(); }
|
|
};
|
|
|
|
// LogMultilineUpToN(max_elements) formats the same as LogMultiline but
|
|
// prints no more than max_elements elements.
|
|
class LogMultilineUpToN : public internal::LogMultilineBase {
|
|
public:
|
|
explicit LogMultilineUpToN(int64_t max_elements)
|
|
: max_elements_(max_elements) {}
|
|
int64_t MaxElements() const { return max_elements_; }
|
|
|
|
private:
|
|
int64_t max_elements_;
|
|
};
|
|
|
|
// LogMultilineUpTo100 formats the same as LogMultiline but
|
|
// prints no more than 100 elements.
|
|
struct LogMultilineUpTo100 : public LogMultilineUpToN {
|
|
LogMultilineUpTo100() : LogMultilineUpToN(100) {}
|
|
};
|
|
|
|
// The legacy behavior of LogSequence() does not use braces and
|
|
// separates items with spaces. For example "1 2 3".
|
|
struct LogLegacyUpTo100 : public internal::LogLegacyBase {
|
|
int64_t MaxElements() const { return 100; }
|
|
};
|
|
struct LogLegacy : public internal::LogLegacyBase {
|
|
int64_t MaxElements() const { return (std::numeric_limits<int64_t>::max)(); }
|
|
};
|
|
|
|
// The default policy for new code.
|
|
typedef LogShortUpTo100 LogDefault;
|
|
|
|
// LogRangeToStream should be used to define operator<< for
|
|
// STL and STL-like containers. For example, see stl_logging.h.
|
|
template <typename IteratorT, typename PolicyT>
|
|
inline void LogRangeToStream(std::ostream &out, // NOLINT
|
|
IteratorT begin, IteratorT end,
|
|
const PolicyT &policy) {
|
|
policy.LogOpening(out);
|
|
for (int64_t i = 0; begin != end && i < policy.MaxElements(); ++i, ++begin) {
|
|
if (i == 0) {
|
|
policy.LogFirstSeparator(out);
|
|
} else {
|
|
policy.LogSeparator(out);
|
|
}
|
|
policy.Log(out, *begin);
|
|
}
|
|
if (begin != end) {
|
|
policy.LogSeparator(out);
|
|
policy.LogEllipsis(out);
|
|
}
|
|
policy.LogClosing(out);
|
|
}
|
|
|
|
namespace detail {
|
|
|
|
// RangeLogger is a helper class for LogRange and LogContainer; do not use it
|
|
// directly. This object captures iterators into the argument of the LogRange
|
|
// and LogContainer functions, so its lifetime should be confined to a single
|
|
// logging statement. Objects of this type should not be assigned to local
|
|
// variables.
|
|
template <typename IteratorT, typename PolicyT>
|
|
class RangeLogger {
|
|
public:
|
|
RangeLogger(const IteratorT &begin, const IteratorT &end,
|
|
const PolicyT &policy)
|
|
: begin_(begin), end_(end), policy_(policy) {}
|
|
|
|
friend std::ostream &operator<<(std::ostream &out, const RangeLogger &range) {
|
|
LogRangeToStream<IteratorT, PolicyT>(out, range.begin_, range.end_,
|
|
range.policy_);
|
|
return out;
|
|
}
|
|
|
|
// operator<< above is generally recommended. However, some situations may
|
|
// require a string, so a convenience str() method is provided as well.
|
|
std::string str() const {
|
|
std::stringstream ss;
|
|
ss << *this;
|
|
return ss.str();
|
|
}
|
|
|
|
private:
|
|
IteratorT begin_;
|
|
IteratorT end_;
|
|
PolicyT policy_;
|
|
};
|
|
|
|
template <typename E>
|
|
class EnumLogger {
|
|
public:
|
|
explicit EnumLogger(E e) : e_(e) {}
|
|
|
|
friend std::ostream &operator<<(std::ostream &out, const EnumLogger &v) {
|
|
using I = typename std::underlying_type<E>::type;
|
|
return out << static_cast<I>(v.e_);
|
|
}
|
|
|
|
private:
|
|
E e_;
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
// Log a range using "policy". For example:
|
|
//
|
|
// LOG(INFO) << LogRange(start_pos, end_pos, LogMultiline());
|
|
//
|
|
// The above example will print the range using newlines between
|
|
// elements, enclosed in [] braces.
|
|
template <typename IteratorT, typename PolicyT>
|
|
detail::RangeLogger<IteratorT, PolicyT> LogRange(const IteratorT &begin,
|
|
const IteratorT &end,
|
|
const PolicyT &policy) {
|
|
return detail::RangeLogger<IteratorT, PolicyT>(begin, end, policy);
|
|
}
|
|
|
|
// Log a range. For example:
|
|
//
|
|
// LOG(INFO) << LogRange(start_pos, end_pos);
|
|
//
|
|
// By default, Range() uses the LogShortUpTo100 policy: comma-space
|
|
// separation, no newlines, and with limit of 100 items.
|
|
template <typename IteratorT>
|
|
detail::RangeLogger<IteratorT, LogDefault> LogRange(const IteratorT &begin,
|
|
const IteratorT &end) {
|
|
return LogRange(begin, end, LogDefault());
|
|
}
|
|
|
|
// Log a container using "policy". For example:
|
|
//
|
|
// LOG(INFO) << LogContainer(container, LogMultiline());
|
|
//
|
|
// The above example will print the container using newlines between
|
|
// elements, enclosed in [] braces.
|
|
template <typename ContainerT, typename PolicyT>
|
|
auto LogContainer(const ContainerT& container, const PolicyT& policy)
|
|
-> decltype(LogRange(container.begin(), container.end(), policy)) {
|
|
return LogRange(container.begin(), container.end(), policy);
|
|
}
|
|
|
|
// Log a container. For example:
|
|
//
|
|
// LOG(INFO) << LogContainer(container);
|
|
//
|
|
// By default, Container() uses the LogShortUpTo100 policy: comma-space
|
|
// separation, no newlines, and with limit of 100 items.
|
|
template <typename ContainerT>
|
|
auto LogContainer(const ContainerT& container)
|
|
-> decltype(LogContainer(container, LogDefault())) {
|
|
return LogContainer(container, LogDefault());
|
|
}
|
|
|
|
// Log a (possibly scoped) enum. For example:
|
|
//
|
|
// enum class Color { kRed, kGreen, kBlue };
|
|
// LOG(INFO) << LogEnum(kRed);
|
|
template <typename E>
|
|
detail::EnumLogger<E> LogEnum(E e) {
|
|
static_assert(std::is_enum<E>::value, "must be an enum");
|
|
return detail::EnumLogger<E>(e);
|
|
}
|
|
|
|
} // namespace log_internal
|
|
ABSL_NAMESPACE_END
|
|
} // namespace absl
|
|
|
|
#endif // ABSL_LOG_INTERNAL_CONTAINER_H_
|