1 //===- FormatVariadicDetails.h - Helpers for FormatVariadic.h ----*- C++-*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_SUPPORT_FORMATVARIADIC_DETAILS_H
10 #define LLVM_SUPPORT_FORMATVARIADIC_DETAILS_H
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/Support/raw_ostream.h"
15 #include <type_traits>
18 template <typename T
, typename Enable
= void> struct format_provider
{};
22 class format_adapter
{
23 virtual void anchor();
26 virtual ~format_adapter() {}
29 virtual void format(raw_ostream
&S
, StringRef Options
) = 0;
32 template <typename T
> class provider_format_adapter
: public format_adapter
{
36 explicit provider_format_adapter(T
&&Item
) : Item(std::forward
<T
>(Item
)) {}
38 void format(llvm::raw_ostream
&S
, StringRef Options
) override
{
39 format_provider
<typename
std::decay
<T
>::type
>::format(Item
, S
, Options
);
44 class stream_operator_format_adapter
: public format_adapter
{
48 explicit stream_operator_format_adapter(T
&&Item
)
49 : Item(std::forward
<T
>(Item
)) {}
51 void format(llvm::raw_ostream
&S
, StringRef Options
) override
{ S
<< Item
; }
54 template <typename T
> class missing_format_adapter
;
56 // Test if format_provider<T> is defined on T and contains a member function
57 // with the signature:
58 // static void format(const T&, raw_stream &, StringRef);
60 template <class T
> class has_FormatProvider
{
62 using Decayed
= typename
std::decay
<T
>::type
;
63 typedef void (*Signature_format
)(const Decayed
&, llvm::raw_ostream
&,
67 static char test(SameType
<Signature_format
, &U::format
> *);
69 template <typename U
> static double test(...);
71 static bool const value
=
72 (sizeof(test
<llvm::format_provider
<Decayed
>>(nullptr)) == 1);
75 // Test if raw_ostream& << T -> raw_ostream& is findable via ADL.
76 template <class T
> class has_StreamOperator
{
78 using ConstRefT
= const typename
std::decay
<T
>::type
&;
81 static char test(typename
std::enable_if
<
82 std::is_same
<decltype(std::declval
<llvm::raw_ostream
&>()
83 << std::declval
<U
>()),
84 llvm::raw_ostream
&>::value
,
87 template <typename U
> static double test(...);
89 static bool const value
= (sizeof(test
<ConstRefT
>(nullptr)) == 1);
92 // Simple template that decides whether a type T should use the member-function
93 // based format() invocation.
95 struct uses_format_member
96 : public std::integral_constant
<
98 std::is_base_of
<format_adapter
,
99 typename
std::remove_reference
<T
>::type
>::value
> {};
101 // Simple template that decides whether a type T should use the format_provider
102 // based format() invocation. The member function takes priority, so this test
103 // will only be true if there is not ALSO a format member.
104 template <typename T
>
105 struct uses_format_provider
106 : public std::integral_constant
<
107 bool, !uses_format_member
<T
>::value
&& has_FormatProvider
<T
>::value
> {
110 // Simple template that decides whether a type T should use the operator<<
111 // based format() invocation. This takes last priority.
112 template <typename T
>
113 struct uses_stream_operator
114 : public std::integral_constant
<bool, !uses_format_member
<T
>::value
&&
115 !uses_format_provider
<T
>::value
&&
116 has_StreamOperator
<T
>::value
> {};
118 // Simple template that decides whether a type T has neither a member-function
119 // nor format_provider based implementation that it can use. Mostly used so
120 // that the compiler spits out a nice diagnostic when a type with no format
121 // implementation can be located.
122 template <typename T
>
123 struct uses_missing_provider
124 : public std::integral_constant
<bool, !uses_format_member
<T
>::value
&&
125 !uses_format_provider
<T
>::value
&&
126 !uses_stream_operator
<T
>::value
> {
129 template <typename T
>
130 typename
std::enable_if
<uses_format_member
<T
>::value
, T
>::type
131 build_format_adapter(T
&&Item
) {
132 return std::forward
<T
>(Item
);
135 template <typename T
>
136 typename
std::enable_if
<uses_format_provider
<T
>::value
,
137 provider_format_adapter
<T
>>::type
138 build_format_adapter(T
&&Item
) {
139 return provider_format_adapter
<T
>(std::forward
<T
>(Item
));
142 template <typename T
>
143 typename
std::enable_if
<uses_stream_operator
<T
>::value
,
144 stream_operator_format_adapter
<T
>>::type
145 build_format_adapter(T
&&Item
) {
146 // If the caller passed an Error by value, then stream_operator_format_adapter
147 // would be responsible for consuming it.
148 // Make the caller opt into this by calling fmt_consume().
150 !std::is_same
<llvm::Error
, typename
std::remove_cv
<T
>::type
>::value
,
151 "llvm::Error-by-value must be wrapped in fmt_consume() for formatv");
152 return stream_operator_format_adapter
<T
>(std::forward
<T
>(Item
));
155 template <typename T
>
156 typename
std::enable_if
<uses_missing_provider
<T
>::value
,
157 missing_format_adapter
<T
>>::type
158 build_format_adapter(T
&&Item
) {
159 return missing_format_adapter
<T
>();