#ifndef ABSL_STRINGS_INTERNAL_GENERIC_PRINTER_INTERNAL_H_
#define ABSL_STRINGS_INTERNAL_GENERIC_PRINTER_INTERNAL_H_
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <ostream>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>
#include "absl/base/config.h"
#include "absl/log/internal/container.h"
#include "absl/meta/internal/requires.h"
#include "absl/strings/has_absl_stringify.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace internal_generic_printer {
template <typename T>
std::ostream& GenericPrintImpl(std::ostream& os, const T& v);
struct Anonymous;
std::ostream& operator<<(const Anonymous&, const Anonymous&) = delete;
struct ContainerLogPolicy {
void LogOpening(std::ostream& os) const { os << "["; }
void LogClosing(std::ostream& os) const { os << "]"; }
void LogFirstSeparator(std::ostream& os) const { os << ""; }
void LogSeparator(std::ostream& os) const { os << ", "; }
int64_t MaxElements() const { return 15; }
template <typename T>
void Log(std::ostream& os, const T& element) const {
internal_generic_printer::GenericPrintImpl(os, element);
}
void LogEllipsis(std::ostream& os) const { os << "..."; }
};
std::ostream& PrintEscapedString(std::ostream& os, absl::string_view v);
template <class T>
inline constexpr bool is_any_string = false;
template <class A>
inline constexpr bool
is_any_string<std::basic_string<char, std::char_traits<char>, A>> = true;
template <class T, class = void>
inline constexpr bool is_supported_ptr = false;
template <class A, class... Deleter>
inline constexpr bool is_supported_ptr<std::unique_ptr<A, Deleter...>> = true;
template <class T>
inline constexpr bool is_supported_ptr<
T,
decltype(T().~ArenaSafeUniquePtr())> = true;
std::ostream& PrintPreciseFP(std::ostream& os, float v);
std::ostream& PrintPreciseFP(std::ostream& os, double v);
std::ostream& PrintPreciseFP(std::ostream& os, long double v);
std::ostream& PrintChar(std::ostream& os, char c);
std::ostream& PrintChar(std::ostream& os, signed char c);
std::ostream& PrintChar(std::ostream& os, unsigned char c);
std::ostream& PrintByte(std::ostream& os, std::byte b);
template <class... Ts>
std::ostream& PrintTuple(std::ostream& os, const std::tuple<Ts...>& tuple) {
absl::string_view sep = "";
const auto print_one = [&](const auto& v) {
os << sep;
(GenericPrintImpl)(os, v);
sep = ", ";
};
os << "<";
std::apply([&](const auto&... v) { (print_one(v), ...); }, tuple);
os << ">";
return os;
}
template <typename T, typename U>
std::ostream& PrintPair(std::ostream& os, const std::pair<T, U>& p) {
os << "<";
(GenericPrintImpl)(os, p.first);
os << ", ";
(GenericPrintImpl)(os, p.second);
os << ">";
return os;
}
template <typename T>
std::ostream& PrintOptionalLike(std::ostream& os, const T& v) {
if (v.has_value()) {
os << "<";
(GenericPrintImpl)(os, *v);
os << ">";
} else {
(GenericPrintImpl)(os, std::nullopt);
}
return os;
}
template <typename... Ts>
std::ostream& PrintVariant(std::ostream& os, const std::variant<Ts...>& v) {
os << "(";
os << "'(index = " << v.index() << ")' ";
std::visit([&](const auto& arg) { (GenericPrintImpl)(os, arg); }, v);
os << ")";
return os;
}
template <typename StatusOrLike>
std::ostream& PrintStatusOrLike(std::ostream& os, const StatusOrLike& v) {
os << "<";
if (v.ok()) {
os << "OK: ";
(GenericPrintImpl)(os, *v);
} else {
(GenericPrintImpl)(os, v.status());
}
os << ">";
return os;
}
template <typename SmartPointer>
std::ostream& PrintSmartPointerContents(std::ostream& os,
const SmartPointer& v) {
os << "<";
if (v == nullptr) {
(GenericPrintImpl)(os, nullptr);
} else {
os << absl::implicit_cast<const void*>(v.get()) << " pointing to ";
if constexpr (meta_internal::Requires<SmartPointer>(
[](auto&& p) -> decltype(p[0]) {})) {
os << "an array";
} else if constexpr (std::is_object_v<
typename SmartPointer::element_type>) {
(GenericPrintImpl)(os, *v);
} else {
os << "a non-object type";
}
}
os << ">";
return os;
}
template <typename T>
std::ostream& GenericPrintImpl(std::ostream& os, const T& v) {
if constexpr (is_any_string<T> || std::is_same_v<T, absl::string_view>) {
return PrintEscapedString(os, v);
} else if constexpr (absl::HasAbslStringify<T>::value) {
return os << absl::StrCat(v);
} else if constexpr (meta_internal::Requires<const T>(
[&](auto&& w)
-> decltype((
PrintTuple)(std::declval<std::ostream&>(),
w)) {})) {
return (PrintTuple)(os, v);
} else if constexpr (meta_internal::Requires<const T>(
[&](auto&& w)
-> decltype((
PrintPair)(std::declval<std::ostream&>(),
w)) {})) {
return (PrintPair)(os, v);
} else if constexpr (meta_internal::Requires<const T>(
[&](auto&& w)
-> decltype((
PrintVariant)(std::declval<std::ostream&>(),
w)) {})) {
return (PrintVariant)(os, v);
} else if constexpr (is_supported_ptr<T>) {
return (PrintSmartPointerContents)(os, v);
} else if constexpr (meta_internal::Requires<const T>(
[&](auto&& w) -> decltype(w.ok(), w.status(), *w) {
})) {
return (PrintStatusOrLike)(os, v);
} else if constexpr (meta_internal::Requires<const T>(
[&](auto&& w) -> decltype(w.has_value(), *w) {})) {
return (PrintOptionalLike)(os, v);
} else if constexpr (std::is_same_v<T, std::nullopt_t>) {
return os << "nullopt";
} else if constexpr (std::is_same_v<T, std::nullptr_t>) {
return os << "nullptr";
} else if constexpr (std::is_floating_point_v<T>) {
return PrintPreciseFP(os, v);
} else if constexpr (std::is_same_v<T, char> ||
std::is_same_v<T, signed char> ||
std::is_same_v<T, unsigned char>) {
return PrintChar(os, v);
} else if constexpr (std::is_same_v<T, std::byte>) {
return PrintByte(os, v);
} else if constexpr (std::is_same_v<T, bool> ||
std::is_same_v<T,
typename std::vector<bool>::reference> ||
std::is_same_v<
T, typename std::vector<bool>::const_reference>) {
return os << (v ? "true" : "false");
} else if constexpr (meta_internal::Requires<const T>(
[&](auto&& w)
-> decltype(ProtobufInternalGetEnumDescriptor(
w)) {})) {
os << static_cast<std::underlying_type_t<T>>(v);
if (auto* desc =
ProtobufInternalGetEnumDescriptor(T{})->FindValueByNumber(v)) {
os << "(" << desc->name() << ")";
}
return os;
} else if constexpr (!std::is_enum_v<T> &&
meta_internal::Requires<const T>(
[&](auto&& w) -> decltype(absl::StrCat(w)) {})) {
return os << absl::StrCat(v);
} else if constexpr (meta_internal::Requires<const T>(
[&](auto&& w)
-> decltype(std::declval<std::ostream&>()
<< log_internal::LogContainer(w)) {
})) {
return os << log_internal::LogContainer(v, ContainerLogPolicy());
} else if constexpr (meta_internal::Requires<const T>(
[&](auto&& w)
-> decltype(std::declval<std::ostream&>() << w) {
})) {
return os << v;
} else if constexpr (meta_internal::Requires<const T>(
[&](auto&& w)
-> decltype(std::declval<std::ostream&>()
<< w.DebugString()) {})) {
return os << v.DebugString();
} else if constexpr (std::is_enum_v<T>) {
return GenericPrintImpl(os, static_cast<std::underlying_type_t<T>>(v));
} else {
return os << "[unprintable value of size " << sizeof(T) << " @" << &v
<< "]";
}
}
template <typename T>
class GenericPrinter {
public:
explicit GenericPrinter(const T& value) : value_(value) {}
private:
friend std::ostream& operator<<(std::ostream& os, const GenericPrinter& gp) {
return internal_generic_printer::GenericPrintImpl(os, gp.value_);
}
const T& value_;
};
struct GenericPrintStreamAdapter {
template <class StreamT>
struct Impl {
template <typename T>
Impl&& operator<<(const T& value) && {
os << internal_generic_printer::GenericPrinter<T>(value);
return std::move(*this);
}
template <typename T>
Impl& operator<<(const T& value) & = delete;
template <typename T>
class HasFlushMethod {
private:
template <typename C>
static std::true_type Test(decltype(&C::Flush));
template <typename C>
static std::false_type Test(...);
public:
static constexpr bool value = decltype(Test<T>(nullptr))::value;
};
void Flush() {
if constexpr (HasFlushMethod<StreamT>::value) {
os.Flush();
}
}
StreamT& os;
};
template <typename LHS, typename RHS>
friend auto operator&&(LHS&& lhs, Impl<RHS>&& rhs)
-> decltype(lhs && rhs.os) {
return lhs && rhs.os;
}
template <class StreamT>
friend Impl<StreamT> operator<<(StreamT& os, GenericPrintStreamAdapter&&) {
return Impl<StreamT>{os};
}
};
struct GenericPrintAdapterFactory {
internal_generic_printer::GenericPrintStreamAdapter operator()() const {
return internal_generic_printer::GenericPrintStreamAdapter{};
}
template <typename T>
internal_generic_printer::GenericPrinter<T> operator()(const T& value) const {
return internal_generic_printer::GenericPrinter<T>{value};
}
};
} ABSL_NAMESPACE_END
}
#endif