FormatVariadicDetails.h revision 341825
1168457Skato//===- FormatVariadicDetails.h - Helpers for FormatVariadic.h ----*- C++-*-===//
264123Skato//
364123Skato//                     The LLVM Compiler Infrastructure
464123Skato//
564123Skato// This file is distributed under the University of Illinois Open Source
664123Skato// License. See LICENSE.TXT for details.
764123Skato//
864123Skato//===----------------------------------------------------------------------===//
964123Skato
1064123Skato#ifndef LLVM_SUPPORT_FORMATVARIADIC_DETAILS_H
1164123Skato#define LLVM_SUPPORT_FORMATVARIADIC_DETAILS_H
1264123Skato
1364123Skato#include "llvm/ADT/StringRef.h"
1464123Skato#include "llvm/Support/raw_ostream.h"
1564123Skato
1664123Skato#include <type_traits>
1764123Skato
1864123Skatonamespace llvm {
1964123Skatotemplate <typename T, typename Enable = void> struct format_provider {};
2064123Skatoclass Error;
2164123Skato
2264123Skatonamespace detail {
2364123Skatoclass format_adapter {
2464123Skatoprotected:
2564123Skato  virtual ~format_adapter() {}
2664123Skato
2764123Skatopublic:
2864123Skato  virtual void format(raw_ostream &S, StringRef Options) = 0;
2964123Skato};
3064123Skato
3164123Skatotemplate <typename T> class provider_format_adapter : public format_adapter {
3264123Skato  T Item;
3364123Skato
3464123Skatopublic:
3564123Skato  explicit provider_format_adapter(T &&Item) : Item(std::forward<T>(Item)) {}
3664123Skato
3764123Skato  void format(llvm::raw_ostream &S, StringRef Options) override {
3864123Skato    format_provider<typename std::decay<T>::type>::format(Item, S, Options);
3964123Skato  }
4064123Skato};
4164123Skato
4264123Skatotemplate <typename T>
4364123Skatoclass stream_operator_format_adapter : public format_adapter {
4464123Skato  T Item;
4564123Skato
4664123Skatopublic:
4764123Skato  explicit stream_operator_format_adapter(T &&Item)
4864123Skato      : Item(std::forward<T>(Item)) {}
4964123Skato
5064123Skato  void format(llvm::raw_ostream &S, StringRef Options) override { S << Item; }
5164123Skato};
5264123Skato
5364123Skatotemplate <typename T> class missing_format_adapter;
5464123Skato
5564123Skato// Test if format_provider<T> is defined on T and contains a member function
5664123Skato// with the signature:
5764123Skato//   static void format(const T&, raw_stream &, StringRef);
5864123Skato//
5964123Skatotemplate <class T> class has_FormatProvider {
6064123Skatopublic:
6164123Skato  using Decayed = typename std::decay<T>::type;
6264123Skato  typedef void (*Signature_format)(const Decayed &, llvm::raw_ostream &,
63167657Skato                                   StringRef);
6464123Skato
6564123Skato  template <typename U>
6664123Skato  static char test(SameType<Signature_format, &U::format> *);
6764123Skato
6864123Skato  template <typename U> static double test(...);
6964123Skato
7064123Skato  static bool const value =
7164123Skato      (sizeof(test<llvm::format_provider<Decayed>>(nullptr)) == 1);
7264123Skato};
7364123Skato
7464123Skato// Test if raw_ostream& << T -> raw_ostream& is findable via ADL.
7564123Skatotemplate <class T> class has_StreamOperator {
7664123Skatopublic:
7764123Skato  using ConstRefT = const typename std::decay<T>::type &;
7864123Skato
7964123Skato  template <typename U>
8064123Skato  static char test(typename std::enable_if<
8164123Skato                   std::is_same<decltype(std::declval<llvm::raw_ostream &>()
8264123Skato                                         << std::declval<U>()),
8364123Skato                                llvm::raw_ostream &>::value,
8464123Skato                   int *>::type);
8564123Skato
8664123Skato  template <typename U> static double test(...);
8764123Skato
8864123Skato  static bool const value = (sizeof(test<ConstRefT>(nullptr)) == 1);
8964123Skato};
9064123Skato
9164123Skato// Simple template that decides whether a type T should use the member-function
9264123Skato// based format() invocation.
9364123Skatotemplate <typename T>
9464123Skatostruct uses_format_member
9564123Skato    : public std::integral_constant<
9664123Skato          bool,
9764123Skato          std::is_base_of<format_adapter,
9864123Skato                          typename std::remove_reference<T>::type>::value> {};
9964123Skato
10064123Skato// Simple template that decides whether a type T should use the format_provider
10164123Skato// based format() invocation.  The member function takes priority, so this test
10264123Skato// will only be true if there is not ALSO a format member.
10364123Skatotemplate <typename T>
10464123Skatostruct uses_format_provider
10564123Skato    : public std::integral_constant<
10664123Skato          bool, !uses_format_member<T>::value && has_FormatProvider<T>::value> {
10764123Skato};
10864123Skato
10964123Skato// Simple template that decides whether a type T should use the operator<<
11064123Skato// based format() invocation.  This takes last priority.
11164123Skatotemplate <typename T>
11264123Skatostruct uses_stream_operator
11364123Skato    : public std::integral_constant<bool, !uses_format_member<T>::value &&
11464123Skato                                              !uses_format_provider<T>::value &&
11564123Skato                                              has_StreamOperator<T>::value> {};
11664123Skato
11764123Skato// Simple template that decides whether a type T has neither a member-function
11864123Skato// nor format_provider based implementation that it can use.  Mostly used so
11964123Skato// that the compiler spits out a nice diagnostic when a type with no format
12064123Skato// implementation can be located.
12164123Skatotemplate <typename T>
12264123Skatostruct uses_missing_provider
12364123Skato    : public std::integral_constant<bool, !uses_format_member<T>::value &&
12464123Skato                                              !uses_format_provider<T>::value &&
12564123Skato                                              !uses_stream_operator<T>::value> {
12664123Skato};
12764123Skato
12864295Skatotemplate <typename T>
12964123Skatotypename std::enable_if<uses_format_member<T>::value, T>::type
13064123Skatobuild_format_adapter(T &&Item) {
13164123Skato  return std::forward<T>(Item);
13264123Skato}
13364123Skato
13464123Skatotemplate <typename T>
13564123Skatotypename std::enable_if<uses_format_provider<T>::value,
13664123Skato                        provider_format_adapter<T>>::type
13764123Skatobuild_format_adapter(T &&Item) {
13864123Skato  return provider_format_adapter<T>(std::forward<T>(Item));
13964123Skato}
14064123Skato
14164123Skatotemplate <typename T>
14264123Skatotypename std::enable_if<uses_stream_operator<T>::value,
14364123Skato                        stream_operator_format_adapter<T>>::type
14464123Skatobuild_format_adapter(T &&Item) {
14564123Skato  // If the caller passed an Error by value, then stream_operator_format_adapter
14664123Skato  // would be responsible for consuming it.
14764123Skato  // Make the caller opt into this by calling fmt_consume().
14864123Skato  static_assert(
14964123Skato      !std::is_same<llvm::Error, typename std::remove_cv<T>::type>::value,
15064123Skato      "llvm::Error-by-value must be wrapped in fmt_consume() for formatv");
15164123Skato  return stream_operator_format_adapter<T>(std::forward<T>(Item));
15264123Skato}
15364123Skato
15464123Skatotemplate <typename T>
15564123Skatotypename std::enable_if<uses_missing_provider<T>::value,
15664123Skato                        missing_format_adapter<T>>::type
15764123Skatobuild_format_adapter(T &&Item) {
15864123Skato  return missing_format_adapter<T>();
15964123Skato}
16064123Skato}
16164123Skato}
16264123Skato
16364123Skato#endif
16464123Skato