| 1 | //===-- raw-ostream.h - Support for printing using raw_ostream --*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // This file is not part of gtest, but extends it to support LLVM libraries. |
| 9 | // This is not a public API for testing - it's a detail of LLVM's gtest. |
| 10 | // |
| 11 | // gtest allows providing printers for custom types by defining operator<<. |
| 12 | // In LLVM, operator<< usually takes llvm:raw_ostream& instead of std::ostream&. |
| 13 | // |
| 14 | // This file defines a template printable(V), which returns a version of V that |
| 15 | // can be streamed into a std::ostream. |
| 16 | // |
| 17 | // This interface is chosen so that in the default case (printable(V) is V), |
| 18 | // the main gtest code calls operator<<(OS, V) itself. gtest-printers carefully |
| 19 | // controls the lookup to enable fallback printing (see testing::internal2). |
| 20 | //===----------------------------------------------------------------------===// |
| 21 | |
| 22 | #ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_RAW_OSTREAM_H_ |
| 23 | #define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_RAW_OSTREAM_H_ |
| 24 | |
| 25 | namespace llvm_gtest { |
| 26 | // StreamSwitch is a trait that tells us how to stream a T into a std::ostream. |
| 27 | // By default, we just stream the T directly. We'll specialize this later. |
| 28 | template <typename T, typename Enable = void> struct StreamSwitch { |
| 29 | static const T& printable(const T& V) { return V; } |
| 30 | }; |
| 31 | |
| 32 | // printable() returns a version of its argument that can be streamed into a |
| 33 | // std::ostream. This may be the argument itself, or some other representation. |
| 34 | template <typename T> decltype(auto) printable(const T &V) { |
| 35 | // We delegate to the trait, to allow partial specialization. |
| 36 | return StreamSwitch<T>::printable(V); |
| 37 | } |
| 38 | } // namespace llvm_gtest |
| 39 | |
| 40 | // If raw_ostream support is enabled, we specialize for types with operator<< |
| 41 | // that takes a raw_ostream. |
| 42 | #if !GTEST_NO_LLVM_SUPPORT |
| 43 | #include "llvm/Support/raw_os_ostream.h" |
| 44 | #include "llvm/Support/raw_ostream.h" |
| 45 | #include <optional> |
| 46 | #include <ostream> |
| 47 | namespace llvm_gtest { |
| 48 | |
| 49 | // The printable() of a raw_ostream-enabled type T is a RawStreamProxy<T>. |
| 50 | // It uses raw_os_ostream to write the wrapped value to a std::ostream. |
| 51 | template <typename T> |
| 52 | struct RawStreamProxy { |
| 53 | const T& V; |
| 54 | friend std::ostream &operator<<(std::ostream &S, const RawStreamProxy<T> &V) { |
| 55 | llvm::raw_os_ostream OS(S); |
| 56 | OS << V.V; |
| 57 | return S; |
| 58 | } |
| 59 | }; |
| 60 | |
| 61 | // We enable raw_ostream treatment if `(raw_ostream&) << (const T&)` is valid. |
| 62 | // We don't want implicit conversions on the RHS (e.g. to bool!), so "consume" |
| 63 | // the possible conversion by passing something convertible to const T& instead. |
| 64 | template <typename T> struct ConvertibleTo { operator T(); }; |
| 65 | template <typename T> |
| 66 | struct StreamSwitch<T, decltype((void)(std::declval<llvm::raw_ostream &>() |
| 67 | << ConvertibleTo<const T &>()))> { |
| 68 | static const RawStreamProxy<T> printable(const T &V) { return {V}; } |
| 69 | }; |
| 70 | |
| 71 | // std::optional has a template operator<<, which means it will not accept any |
| 72 | // implicit conversions, so we need to special-case it here. |
| 73 | template <typename T> |
| 74 | struct StreamSwitch<std::optional<T>, |
| 75 | decltype((void)(std::declval<llvm::raw_ostream &>() |
| 76 | << std::declval<std::optional<T>>()))> { |
| 77 | static const RawStreamProxy<std::optional<T>> |
| 78 | printable(const std::optional<T> &V) { |
| 79 | return {V}; |
| 80 | } |
| 81 | }; |
| 82 | } // namespace llvm_gtest |
| 83 | #endif // !GTEST_NO_LLVM_SUPPORT |
| 84 | |
| 85 | #endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_RAW_OSTREAM_H_ |
| 86 | |