1//===- FormatVariadicDetails.h - Helpers for FormatVariadic.h ----*- C++-*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef LLVM_SUPPORT_FORMATVARIADIC_DETAILS_H
11#define LLVM_SUPPORT_FORMATVARIADIC_DETAILS_H
12
13#include "llvm/ADT/StringRef.h"
14#include "llvm/Support/raw_ostream.h"
15
16#include <type_traits>
17
18namespace llvm {
19template <typename T, typename Enable = void> struct format_provider {};
20class Error;
21
22namespace detail {
23class format_adapter {
24 virtual void anchor();
25
26protected:
27 virtual ~format_adapter() {}
28
29public:
30 virtual void format(raw_ostream &S, StringRef Options) = 0;
31};
32
33template <typename T> class provider_format_adapter : public format_adapter {
34 T Item;
35
36public:
37 explicit provider_format_adapter(T &&Item) : Item(std::forward<T>(Item)) {}
38
39 void format(llvm::raw_ostream &S, StringRef Options) override {
40 format_provider<typename std::decay<T>::type>::format(Item, S, Options);
41 }
42};
43
44template <typename T>
45class stream_operator_format_adapter : public format_adapter {
46 T Item;
47
48public:
49 explicit stream_operator_format_adapter(T &&Item)
50 : Item(std::forward<T>(Item)) {}
51
52 void format(llvm::raw_ostream &S, StringRef Options) override { S << Item; }
53};
54
55template <typename T> class missing_format_adapter;
56
57// Test if format_provider<T> is defined on T and contains a member function
58// with the signature:
59// static void format(const T&, raw_stream &, StringRef);
60//
61template <class T> class has_FormatProvider {
62public:
63 using Decayed = typename std::decay<T>::type;
64 typedef void (*Signature_format)(const Decayed &, llvm::raw_ostream &,
65 StringRef);
66
67 template <typename U>
68 static char test(SameType<Signature_format, &U::format> *);
69
70 template <typename U> static double test(...);
71
72 static bool const value =
73 (sizeof(test<llvm::format_provider<Decayed>>(nullptr)) == 1);
74};
75
76// Test if raw_ostream& << T -> raw_ostream& is findable via ADL.
77template <class T> class has_StreamOperator {
78public:
79 using ConstRefT = const typename std::decay<T>::type &;
80
81 template <typename U>
82 static char test(typename std::enable_if<
83 std::is_same<decltype(std::declval<llvm::raw_ostream &>()
84 << std::declval<U>()),
85 llvm::raw_ostream &>::value,
86 int *>::type);
87
88 template <typename U> static double test(...);
89
90 static bool const value = (sizeof(test<ConstRefT>(nullptr)) == 1);
91};
92
93// Simple template that decides whether a type T should use the member-function
94// based format() invocation.
95template <typename T>
96struct uses_format_member
97 : public std::integral_constant<
98 bool,
99 std::is_base_of<format_adapter,
100 typename std::remove_reference<T>::type>::value> {};
101
102// Simple template that decides whether a type T should use the format_provider
103// based format() invocation. The member function takes priority, so this test
104// will only be true if there is not ALSO a format member.
105template <typename T>
106struct uses_format_provider
107 : public std::integral_constant<
108 bool, !uses_format_member<T>::value && has_FormatProvider<T>::value> {
109};
110
111// Simple template that decides whether a type T should use the operator<<
112// based format() invocation. This takes last priority.
113template <typename T>
114struct uses_stream_operator
115 : public std::integral_constant<bool, !uses_format_member<T>::value &&
116 !uses_format_provider<T>::value &&
117 has_StreamOperator<T>::value> {};
118
119// Simple template that decides whether a type T has neither a member-function
120// nor format_provider based implementation that it can use. Mostly used so
121// that the compiler spits out a nice diagnostic when a type with no format
122// implementation can be located.
123template <typename T>
124struct uses_missing_provider
125 : public std::integral_constant<bool, !uses_format_member<T>::value &&
126 !uses_format_provider<T>::value &&
127 !uses_stream_operator<T>::value> {
128};
129
130template <typename T>
131typename std::enable_if<uses_format_member<T>::value, T>::type
132build_format_adapter(T &&Item) {
133 return std::forward<T>(Item);
134}
135
136template <typename T>
137typename std::enable_if<uses_format_provider<T>::value,
138 provider_format_adapter<T>>::type
139build_format_adapter(T &&Item) {
140 return provider_format_adapter<T>(std::forward<T>(Item));
141}
142
143template <typename T>
144typename std::enable_if<uses_stream_operator<T>::value,
145 stream_operator_format_adapter<T>>::type
146build_format_adapter(T &&Item) {
147 // If the caller passed an Error by value, then stream_operator_format_adapter
148 // would be responsible for consuming it.
149 // Make the caller opt into this by calling fmt_consume().
150 static_assert(
151 !std::is_same<llvm::Error, typename std::remove_cv<T>::type>::value,
152 "llvm::Error-by-value must be wrapped in fmt_consume() for formatv");
153 return stream_operator_format_adapter<T>(std::forward<T>(Item));
154}
155
156template <typename T>
157typename std::enable_if<uses_missing_provider<T>::value,
158 missing_format_adapter<T>>::type
159build_format_adapter(T &&Item) {
160 return missing_format_adapter<T>();
161}
162}
163}
164
165#endif
166