ostream.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_COMMON_OSTREAM_H_
  5. #define CARBON_COMMON_OSTREAM_H_
  6. #include <ostream>
  7. #include "common/metaprogramming.h"
  8. #include "llvm/Support/raw_os_ostream.h"
  9. // Libraries should include this header instead of raw_ostream.
  10. #include "llvm/Support/raw_ostream.h" // IWYU pragma: export
  11. namespace Carbon {
  12. // True if T has a method `void Print(llvm::raw_ostream& out) const`.
  13. template <typename T>
  14. static constexpr bool HasPrintMethod = Requires<const T, llvm::raw_ostream>(
  15. [](auto&& t, auto&& out) -> decltype(t.Print(out)) {});
  16. // Support raw_ostream << for types which implement:
  17. // void Print(llvm::raw_ostream& out) const;
  18. template <typename T, typename = std::enable_if_t<HasPrintMethod<T>>>
  19. auto operator<<(llvm::raw_ostream& out, const T& obj) -> llvm::raw_ostream& {
  20. obj.Print(out);
  21. return out;
  22. }
  23. // Prevents raw_ostream << for pointers to printable types.
  24. template <typename T, typename = std::enable_if_t<HasPrintMethod<T>>>
  25. __attribute__((unavailable(
  26. "Received a pointer to a printable type, are you missing a `*`? "
  27. "To print as a pointer, cast to void*."))) auto
  28. operator<<(llvm::raw_ostream& out, const T* /*obj*/) -> llvm::raw_ostream&;
  29. // Support std::ostream << for types which implement:
  30. // void Print(llvm::raw_ostream& out) const;
  31. template <typename T, typename = std::enable_if_t<HasPrintMethod<T>>>
  32. auto operator<<(std::ostream& out, const T& obj) -> std::ostream& {
  33. llvm::raw_os_ostream raw_os(out);
  34. obj.Print(raw_os);
  35. return out;
  36. }
  37. // Prevents std::ostream << for pointers to printable types.
  38. template <typename T, typename = std::enable_if_t<HasPrintMethod<T>>>
  39. __attribute__((unavailable(
  40. "Received a pointer to a printable type, are you missing a `*`? "
  41. "To print as a pointer, cast to void*."))) auto
  42. operator<<(std::ostream& out, const T* /*obj*/) -> std::ostream&;
  43. // Allow GoogleTest and GoogleMock to print even pointers by dereferencing them.
  44. // This is important to allow automatic printing of arguments of mocked APIs.
  45. template <typename T, typename = std::enable_if_t<HasPrintMethod<T>>>
  46. void PrintTo(T* p, std::ostream* out) {
  47. *out << static_cast<const void*>(p);
  48. // Also print the object if non-null.
  49. if (p) {
  50. *out << " pointing to " << *p;
  51. }
  52. }
  53. // Helper to support printing the ID for a type that has a method
  54. // `void PrintID(llvm::raw_ostream& out) const`. Usage:
  55. //
  56. // out << PrintAsID(obj);
  57. template <typename T>
  58. class PrintAsID {
  59. public:
  60. explicit PrintAsID(const T& object) : object_(&object) {}
  61. friend auto operator<<(llvm::raw_ostream& out, const PrintAsID& self)
  62. -> llvm::raw_ostream& {
  63. self.object_->PrintID(out);
  64. return out;
  65. }
  66. private:
  67. const T* object_;
  68. };
  69. template <typename T>
  70. PrintAsID(const T&) -> PrintAsID<T>;
  71. } // namespace Carbon
  72. namespace llvm {
  73. // Injects an `operator<<` overload into the `llvm` namespace which detects LLVM
  74. // types with `raw_ostream` overloads and uses that to map to a `std::ostream`
  75. // overload. This allows LLVM types to be printed to `std::ostream` via their
  76. // `raw_ostream` operator overloads, which is needed both for logging and
  77. // testing.
  78. //
  79. // To make this overload be unusually low priority, it is designed to take even
  80. // the `std::ostream` parameter as a template, and SFINAE disable itself unless
  81. // that template parameter matches `std::ostream`. This ensures that an
  82. // *explicit* operator will be preferred when provided. Some LLVM types may have
  83. // this, and so we want to prioritize accordingly.
  84. //
  85. // It would be slightly cleaner for LLVM itself to provide this overload in
  86. // `raw_os_ostream.h` so that we wouldn't need to inject into LLVM's namespace,
  87. // but supporting `std::ostream` isn't a priority for LLVM so we handle it
  88. // locally instead.
  89. template <typename S, typename T,
  90. typename = std::enable_if_t<std::is_base_of_v<
  91. std::ostream, std::remove_reference_t<std::remove_cv_t<S>>>>,
  92. typename = std::enable_if_t<!std::is_same_v<
  93. std::remove_reference_t<std::remove_cv_t<T>>, raw_ostream>>>
  94. auto operator<<(S& standard_out, const T& value) -> S& {
  95. raw_os_ostream(standard_out) << value;
  96. return standard_out;
  97. }
  98. } // namespace llvm
  99. #endif // CARBON_COMMON_OSTREAM_H_