| 58 | namespace strings_internal { |
| 59 | |
| 60 | class StringifyStream { |
| 61 | public: |
| 62 | // Constructor: adapts (but does not take ownership of) some underlying |
| 63 | // std::ostream instance. |
| 64 | explicit StringifyStream(std::ostream& os) : sink_{os} {} |
| 65 | |
| 66 | // Stream insertion: delegate to an overload of operator<< if defined for type |
| 67 | // T, otherwise fall back to AbslStringify for T. |
| 68 | template <typename T> |
| 69 | friend StringifyStream& operator<<(StringifyStream& stream, const T& t) { |
| 70 | if constexpr (HasStreamInsertion<T>::value) { |
| 71 | stream.sink_.os << t; |
| 72 | } else { |
| 73 | AbslStringify(stream.sink_, t); |
| 74 | } |
| 75 | return stream; |
| 76 | } |
| 77 | |
| 78 | // Rvalue-ref overload, required when the StringifyStream parameter hasn't |
| 79 | // been bound to a variable. |
| 80 | template <typename T> |
| 81 | friend StringifyStream& operator<<(StringifyStream&& stream, const T& t) { |
| 82 | return stream << t; |
| 83 | } |
| 84 | |
| 85 | // Overload for things like << std::endl which need an explicit type in order |
| 86 | // to resolve to the appropriate overload or template instantiation. |
| 87 | StringifyStream& operator<<(std::ostream& (*func)(std::ostream&)) { |
| 88 | sink_.os << func; |
| 89 | return *this; |
| 90 | } |
| 91 | |
| 92 | private: |
| 93 | // Abseil "stringify sink" concept (stringify_sink.h) |
| 94 | struct Sink { |
| 95 | std::ostream& os; |
| 96 | void Append(size_t count, char ch) { os << std::string(count, ch); } |
| 97 | void Append(absl::string_view v) { os << v; } |
| 98 | friend void AbslFormatFlush(Sink* sink, absl::string_view v) { |
| 99 | sink->Append(v); |
| 100 | } |
| 101 | } sink_; |
| 102 | |
| 103 | // SFINAE helper to identify types with a defined operator<< overload. |
| 104 | template <typename T, typename = void> |
| 105 | struct HasStreamInsertion : std::false_type {}; |
| 106 | |
| 107 | template <typename T> |
| 108 | struct HasStreamInsertion<T, |
| 109 | std::void_t<decltype(std::declval<std::ostream&>() |
| 110 | << std::declval<const T&>())>> |
| 111 | : std::true_type {}; |
| 112 | }; |
| 113 | |
| 114 | } // namespace strings_internal |
| 115 | |