18#include "absl/strings/str_cat.h"
19#include "absl/strings/str_format.h"
20#include "absl/types/span.h"
21#include "lib/source_file.h"
22#include "lib/stringify.h"
25namespace FormatDetail {
30std::string normalizeFormat(std::string_view format,
size_t argumentCount);
31std::string formatMessage(std::string_view format, absl::Span<const absl::FormatArg> arguments);
32void setFormatFlags(std::ostream &out,
const absl::FormatConversionSpec &spec);
33bool appendStreamArgument(std::string text,
const absl::FormatConversionSpec &spec,
34 absl::FormatSink *sink,
bool arithmetic);
36template <
bool PreferDbpr
int,
typename T>
37void streamArgument(std::ostream &out,
const T &arg) {
39 using Type = std::remove_cvref_t<T>;
40 if constexpr (std::is_same_v<Type, Util::SourceInfo>) {
42 }
else if constexpr (std::is_same_v<Type, std::nullptr_t>) {
44 }
else if constexpr (std::is_pointer_v<Type>) {
45 using Pointee = std::remove_pointer_t<Type>;
48 }
else if constexpr (std::is_same_v<std::remove_cv_t<Pointee>,
char> ||
49 std::is_void_v<Pointee> || std::is_function_v<Pointee>) {
51 }
else if constexpr (std::is_same_v<std::remove_cv_t<Pointee>, Util::SourceInfo>) {
53 }
else if constexpr (PreferDbprint) {
55 if constexpr (has_dbprint_v<Pointee>) {
61 streamArgument<PreferDbprint>(out, *arg);
63 }
else if constexpr (PreferDbprint && has_dbprint_v<Type>) {
65 }
else if constexpr (!PreferDbprint && Util::has_toString_v<Type>) {
66 out << arg.toString();
68 static_assert(has_ostream_operator_v<T>,
69 "cannot format this type; implement toString, dbprint, or operator<<");
76template <
bool PreferDbpr
int,
typename T>
78 std::reference_wrapper<const T> value;
80 friend absl::FormatConvertResult<
81 absl::FormatConversionCharSet::kString | absl::FormatConversionCharSet::kNumeric |
82 absl::FormatConversionCharSet::c | absl::FormatConversionCharSet::v |
83 absl::FormatConversionCharSet::p>
86 AbslFormatConvert(
const StreamArgument &arg,
const absl::FormatConversionSpec &spec,
87 absl::FormatSink *sink) {
88 std::ostringstream out;
89 setFormatFlags(out, spec);
90 if constexpr (std::is_pointer_v<T> && !std::is_function_v<std::remove_pointer_t<T>>) {
91 if (spec.conversion_char() == absl::FormatConversionChar::p) {
92 out << static_cast<const void *>(arg.value.get());
94 streamArgument<PreferDbprint>(out, arg.value.get());
97 streamArgument<PreferDbprint>(out, arg.value.get());
99 return {appendStreamArgument(out.str(), spec, sink, std::is_arithmetic_v<T>)};
103template <
bool PreferDbpr
int,
typename T>
105 if constexpr (std::is_arithmetic_v<T>) {
106 return absl::FormatArg(arg.value.get());
108 return absl::FormatArg(arg);
112template <
bool PreferDbprint,
typename Tuple,
size_t... Is>
113std::string formatTuple(std::string_view format,
const Tuple &args,
114 [[maybe_unused]] std::index_sequence<Is...> indices) {
115 if constexpr (
sizeof...(Is) == 0) {
117 return formatMessage(format, {});
119 auto adapters = std::tuple{
121 std::get<Is>(args)}...};
122 std::array<absl::FormatArg, 2 *
sizeof...(Is)> arguments{
123 nativeArgument(std::get<Is>(adapters))..., absl::FormatArg(std::get<Is>(adapters))...};
124 return formatMessage(format, arguments);
130template <
typename T,
typename Emit>
131void visitSourceInfo(
const T &arg,
const Emit &emit) {
132 using Type = std::remove_cvref_t<T>;
133 if constexpr (std::is_same_v<Type, Util::SourceInfo>) {
137 }
else if constexpr (std::is_pointer_v<Type>) {
138 if constexpr (!std::is_void_v<std::remove_pointer_t<Type>> &&
139 !std::is_function_v<std::remove_pointer_t<Type>>) {
140 if (arg !=
nullptr) {
141 visitSourceInfo(*arg, emit);
144 }
else if constexpr (Util::has_SourceInfo_v<Type>) {
145 visitSourceInfo(arg.getSourceInfo(), emit);
157template <
bool PreferDbpr
int = false,
typename Tuple>
159 return FormatDetail::formatTuple<PreferDbprint>(
160 format, args, std::make_index_sequence<std::tuple_size_v<Tuple>>{});
163template <
bool PreferDbprint =
false,
typename... Args>
164std::string createFormattedMessage(
const char *format,
const Args &...args) {
168template <
typename... Args>
169std::string createBugMessage(
const char *format,
const Args &...args) {
170 std::string position;
172 if constexpr (
sizeof...(Args) != 0) {
174 auto pos =
info.toPositionString();
175 if (position.empty()) {
177 }
else if (!pos.isNullOrEmpty()) {
178 absl::StrAppend(&tail, pos,
"\n");
180 absl::StrAppend(&tail,
info.toSourceFragment());
182 (FormatDetail::visitSourceInfo(args, collect), ...);
184 return absl::StrCat(position, position.empty() ?
"" :
": ",
185 createFormattedMessage<true>(format, args...),
"\n", tail);
Definition source_file.h:123
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13
std::string createFormattedMessageFromTuple(const char *format, const Tuple &args)
Definition format.h:158
void info(const int kind, const char *format, const T *node, Args &&...args)
Report info messages of type kind. Requires that the node argument have source info.
Definition lib/error.h:157