ostream.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  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 COMMON_OSTREAM_H_
  5. #define COMMON_OSTREAM_H_
  6. #include <ostream>
  7. #include "common/metaprogramming.h"
  8. #include "llvm/Support/raw_os_ostream.h"
  9. #include "llvm/Support/raw_ostream.h"
  10. namespace Carbon {
  11. // True if T has a method `void Print(llvm::raw_ostream& out) const`.
  12. template <typename T>
  13. static constexpr bool HasPrintMethod = Requires<const T, llvm::raw_ostream>(
  14. [](auto&& t, auto&& out) -> decltype(t.Print(out)) {});
  15. // Support raw_ostream << for types which implement:
  16. // void Print(llvm::raw_ostream& out) const;
  17. template <typename T, typename = std::enable_if_t<HasPrintMethod<T>>>
  18. auto operator<<(llvm::raw_ostream& out, const T& obj) -> llvm::raw_ostream& {
  19. obj.Print(out);
  20. return out;
  21. }
  22. // Prevents raw_ostream << for pointers to printable types.
  23. template <typename T, typename = std::enable_if_t<HasPrintMethod<T>>>
  24. __attribute__((unavailable(
  25. "Received a pointer to a printable type, are you missing a `*`? "
  26. "To print as a pointer, cast to void*."))) auto
  27. operator<<(llvm::raw_ostream& out, const T* /*obj*/) -> llvm::raw_ostream&;
  28. // Support std::ostream << for types which implement:
  29. // void Print(llvm::raw_ostream& out) const;
  30. template <typename T, typename = std::enable_if_t<HasPrintMethod<T>>>
  31. auto operator<<(std::ostream& out, const T& obj) -> std::ostream& {
  32. llvm::raw_os_ostream raw_os(out);
  33. obj.Print(raw_os);
  34. return out;
  35. }
  36. // Prevents std::ostream << for pointers to printable types.
  37. template <typename T, typename = std::enable_if_t<HasPrintMethod<T>>>
  38. __attribute__((unavailable(
  39. "Received a pointer to a printable type, are you missing a `*`? "
  40. "To print as a pointer, cast to void*."))) auto
  41. operator<<(std::ostream& out, const T* /*obj*/) -> std::ostream&;
  42. // Allow GoogleTest and GoogleMock to print even pointers by dereferencing them.
  43. // This is important to allow automatic printing of arguments of mocked APIs.
  44. template <typename T, typename = std::enable_if_t<HasPrintMethod<T>>>
  45. void PrintTo(T* p, std::ostream* out) {
  46. *out << static_cast<const void*>(p);
  47. // Also print the object if non-null.
  48. if (p) {
  49. *out << " pointing to " << *p;
  50. }
  51. }
  52. } // namespace Carbon
  53. namespace llvm {
  54. // Injects an `operator<<` overload into the `llvm` namespace which detects LLVM
  55. // types with `raw_ostream` overloads and uses that to map to a `std::ostream`
  56. // overload. This allows LLVM types to be printed to `std::ostream` via their
  57. // `raw_ostream` operator overloads, which is needed both for logging and
  58. // testing.
  59. //
  60. // To make this overload be unusually low priority, it is designed to take even
  61. // the `std::ostream` parameter as a template, and SFINAE disable itself unless
  62. // that template parameter matches `std::ostream`. This ensures that an
  63. // *explicit* operator will be preferred when provided. Some LLVM types may have
  64. // this, and so we want to prioritize accordingly.
  65. //
  66. // It would be slightly cleaner for LLVM itself to provide this overload in
  67. // `raw_os_ostream.h` so that we wouldn't need to inject into its namespace, but
  68. // supporting `std::ostream` isn't a priority for LLVM so we handle it locally
  69. // instead.
  70. template <typename S, typename T,
  71. typename = std::enable_if_t<std::is_base_of_v<
  72. std::ostream, std::remove_reference_t<std::remove_cv_t<S>>>>,
  73. typename = std::enable_if_t<!std::is_same_v<
  74. std::remove_reference_t<std::remove_cv_t<T>>, raw_ostream>>>
  75. auto operator<<(S& standard_out, const T& value) -> S& {
  76. raw_os_ostream(standard_out) << value;
  77. return standard_out;
  78. }
  79. } // namespace llvm
  80. #endif // COMMON_OSTREAM_H_