1311116Sdim//===- FormatVariadicDetails.h - Helpers for FormatVariadic.h ----*- C++-*-===// 2311116Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6311116Sdim// 7311116Sdim//===----------------------------------------------------------------------===// 8311116Sdim 9311116Sdim#ifndef LLVM_SUPPORT_FORMATVARIADIC_DETAILS_H 10311116Sdim#define LLVM_SUPPORT_FORMATVARIADIC_DETAILS_H 11311116Sdim 12311116Sdim#include "llvm/ADT/StringRef.h" 13311116Sdim#include "llvm/Support/raw_ostream.h" 14311116Sdim 15311116Sdim#include <type_traits> 16311116Sdim 17311116Sdimnamespace llvm { 18311116Sdimtemplate <typename T, typename Enable = void> struct format_provider {}; 19341825Sdimclass Error; 20311116Sdim 21311116Sdimnamespace detail { 22311116Sdimclass format_adapter { 23344779Sdim virtual void anchor(); 24344779Sdim 25311116Sdimprotected: 26311116Sdim virtual ~format_adapter() {} 27311116Sdim 28311116Sdimpublic: 29311116Sdim virtual void format(raw_ostream &S, StringRef Options) = 0; 30311116Sdim}; 31311116Sdim 32311116Sdimtemplate <typename T> class provider_format_adapter : public format_adapter { 33311116Sdim T Item; 34311116Sdim 35311116Sdimpublic: 36327952Sdim explicit provider_format_adapter(T &&Item) : Item(std::forward<T>(Item)) {} 37311116Sdim 38311116Sdim void format(llvm::raw_ostream &S, StringRef Options) override { 39311116Sdim format_provider<typename std::decay<T>::type>::format(Item, S, Options); 40311116Sdim } 41311116Sdim}; 42311116Sdim 43341825Sdimtemplate <typename T> 44341825Sdimclass stream_operator_format_adapter : public format_adapter { 45341825Sdim T Item; 46341825Sdim 47341825Sdimpublic: 48341825Sdim explicit stream_operator_format_adapter(T &&Item) 49341825Sdim : Item(std::forward<T>(Item)) {} 50341825Sdim 51341825Sdim void format(llvm::raw_ostream &S, StringRef Options) override { S << Item; } 52341825Sdim}; 53341825Sdim 54311116Sdimtemplate <typename T> class missing_format_adapter; 55311116Sdim 56311116Sdim// Test if format_provider<T> is defined on T and contains a member function 57311116Sdim// with the signature: 58311116Sdim// static void format(const T&, raw_stream &, StringRef); 59311116Sdim// 60311116Sdimtemplate <class T> class has_FormatProvider { 61311116Sdimpublic: 62311116Sdim using Decayed = typename std::decay<T>::type; 63311116Sdim typedef void (*Signature_format)(const Decayed &, llvm::raw_ostream &, 64311116Sdim StringRef); 65311116Sdim 66311116Sdim template <typename U> 67311116Sdim static char test(SameType<Signature_format, &U::format> *); 68311116Sdim 69311116Sdim template <typename U> static double test(...); 70311116Sdim 71311116Sdim static bool const value = 72311116Sdim (sizeof(test<llvm::format_provider<Decayed>>(nullptr)) == 1); 73311116Sdim}; 74311116Sdim 75341825Sdim// Test if raw_ostream& << T -> raw_ostream& is findable via ADL. 76341825Sdimtemplate <class T> class has_StreamOperator { 77341825Sdimpublic: 78341825Sdim using ConstRefT = const typename std::decay<T>::type &; 79341825Sdim 80341825Sdim template <typename U> 81341825Sdim static char test(typename std::enable_if< 82341825Sdim std::is_same<decltype(std::declval<llvm::raw_ostream &>() 83341825Sdim << std::declval<U>()), 84341825Sdim llvm::raw_ostream &>::value, 85341825Sdim int *>::type); 86341825Sdim 87341825Sdim template <typename U> static double test(...); 88341825Sdim 89341825Sdim static bool const value = (sizeof(test<ConstRefT>(nullptr)) == 1); 90341825Sdim}; 91341825Sdim 92311116Sdim// Simple template that decides whether a type T should use the member-function 93311116Sdim// based format() invocation. 94311116Sdimtemplate <typename T> 95311116Sdimstruct uses_format_member 96311116Sdim : public std::integral_constant< 97311116Sdim bool, 98311116Sdim std::is_base_of<format_adapter, 99311116Sdim typename std::remove_reference<T>::type>::value> {}; 100311116Sdim 101311116Sdim// Simple template that decides whether a type T should use the format_provider 102311116Sdim// based format() invocation. The member function takes priority, so this test 103311116Sdim// will only be true if there is not ALSO a format member. 104311116Sdimtemplate <typename T> 105311116Sdimstruct uses_format_provider 106311116Sdim : public std::integral_constant< 107311116Sdim bool, !uses_format_member<T>::value && has_FormatProvider<T>::value> { 108311116Sdim}; 109311116Sdim 110341825Sdim// Simple template that decides whether a type T should use the operator<< 111341825Sdim// based format() invocation. This takes last priority. 112341825Sdimtemplate <typename T> 113341825Sdimstruct uses_stream_operator 114341825Sdim : public std::integral_constant<bool, !uses_format_member<T>::value && 115341825Sdim !uses_format_provider<T>::value && 116341825Sdim has_StreamOperator<T>::value> {}; 117341825Sdim 118311116Sdim// Simple template that decides whether a type T has neither a member-function 119311116Sdim// nor format_provider based implementation that it can use. Mostly used so 120311116Sdim// that the compiler spits out a nice diagnostic when a type with no format 121311116Sdim// implementation can be located. 122311116Sdimtemplate <typename T> 123311116Sdimstruct uses_missing_provider 124341825Sdim : public std::integral_constant<bool, !uses_format_member<T>::value && 125341825Sdim !uses_format_provider<T>::value && 126341825Sdim !uses_stream_operator<T>::value> { 127341825Sdim}; 128311116Sdim 129311116Sdimtemplate <typename T> 130311116Sdimtypename std::enable_if<uses_format_member<T>::value, T>::type 131311116Sdimbuild_format_adapter(T &&Item) { 132311116Sdim return std::forward<T>(Item); 133311116Sdim} 134311116Sdim 135311116Sdimtemplate <typename T> 136311116Sdimtypename std::enable_if<uses_format_provider<T>::value, 137311116Sdim provider_format_adapter<T>>::type 138311116Sdimbuild_format_adapter(T &&Item) { 139311116Sdim return provider_format_adapter<T>(std::forward<T>(Item)); 140311116Sdim} 141311116Sdim 142311116Sdimtemplate <typename T> 143341825Sdimtypename std::enable_if<uses_stream_operator<T>::value, 144341825Sdim stream_operator_format_adapter<T>>::type 145341825Sdimbuild_format_adapter(T &&Item) { 146341825Sdim // If the caller passed an Error by value, then stream_operator_format_adapter 147341825Sdim // would be responsible for consuming it. 148341825Sdim // Make the caller opt into this by calling fmt_consume(). 149341825Sdim static_assert( 150341825Sdim !std::is_same<llvm::Error, typename std::remove_cv<T>::type>::value, 151341825Sdim "llvm::Error-by-value must be wrapped in fmt_consume() for formatv"); 152341825Sdim return stream_operator_format_adapter<T>(std::forward<T>(Item)); 153341825Sdim} 154341825Sdim 155341825Sdimtemplate <typename T> 156311116Sdimtypename std::enable_if<uses_missing_provider<T>::value, 157311116Sdim missing_format_adapter<T>>::type 158311116Sdimbuild_format_adapter(T &&Item) { 159311116Sdim return missing_format_adapter<T>(); 160311116Sdim} 161311116Sdim} 162311116Sdim} 163311116Sdim 164311116Sdim#endif 165