@@ -26,55 +26,107 @@ namespace llvm {
2626// << "] " << "Bitset contains: " << Bitset << "\n");
2727#define LDBG () DEBUGLOG_WITH_STREAM_AND_TYPE(llvm::dbgs(), DEBUG_TYPE)
2828
29- #if defined(__SHORT_FILE__)
30- #define DEBUGLOG_WITH_STREAM_AND_TYPE (STREAM, TYPE ) \
29+ #define DEBUGLOG_WITH_STREAM_TYPE_AND_FILE (STREAM, TYPE, FILE ) \
3130 for (bool _c = (::llvm::DebugFlag && ::llvm::isCurrentDebugType(TYPE)); _c; \
3231 _c = false ) \
33- ::llvm::impl::LogWithNewline (TYPE, __SHORT_FILE__, __LINE__, (STREAM))
32+ ::llvm::impl::raw_ldbg_ostream{ \
33+ ::llvm::impl::computePrefix (TYPE, FILE, __LINE__), (STREAM)} \
34+ .asLvalue ()
35+ // When __SHORT_FILE__ is not defined, the File is the full path,
36+ // otherwise __SHORT_FILE__ is defined in CMake to provide the file name
37+ // without the path prefix.
38+ #if defined(__SHORT_FILE__)
39+ #define DEBUGLOG_WITH_STREAM_AND_TYPE (STREAM, TYPE ) \
40+ DEBUGLOG_WITH_STREAM_TYPE_AND_FILE (STREAM, TYPE, __SHORT_FILE__)
3441#else
3542#define DEBUGLOG_WITH_STREAM_AND_TYPE (STREAM, TYPE ) \
36- for (bool _c = (::llvm::DebugFlag && ::llvm::isCurrentDebugType(TYPE)); _c; \
37- _c = false ) \
38- ::llvm::impl::LogWithNewline (TYPE, __FILE__, __LINE__, (STREAM))
43+ DEBUGLOG_WITH_STREAM_TYPE_AND_FILE ( \
44+ STREAM, TYPE, ::llvm::impl::LogWithNewline::getShortFileName (__FILE__))
3945#endif
4046
4147namespace impl {
42- class LogWithNewline {
43- public:
44- LogWithNewline (const char *debug_type, const char *file, int line,
45- raw_ostream &os)
46- : os(os) {
47- #if !defined(__SHORT_FILE__)
48- file = ::llvm::impl::LogWithNewline::getShortFileName (file);
49- #endif
50- if (debug_type)
51- os << " [" << debug_type << " ] " ;
52- os << file << " :" << line << " " ;
48+
49+ // / A raw_ostream that tracks `\n` and print the prefix.
50+ class LLVM_ABI raw_ldbg_ostream final : public raw_ostream {
51+ std::string Prefix;
52+ raw_ostream &Os;
53+ bool HasPendingNewline = true ;
54+
55+ // / Split the line on newlines and insert the prefix before each newline.
56+ // / Forward everything to the underlying stream.
57+ void write_impl (const char *Ptr, size_t Size) final {
58+ auto Str = StringRef (Ptr, Size);
59+ // Handle the initial prefix.
60+ if (!Str.empty ())
61+ writeWithPrefix (StringRef ());
62+
63+ auto Eol = Str.find (' \n ' );
64+ while (Eol != StringRef::npos) {
65+ StringRef Line = Str.take_front (Eol + 1 );
66+ if (!Line.empty ())
67+ writeWithPrefix (Line);
68+ HasPendingNewline = true ;
69+ Str = Str.drop_front (Eol + 1 );
70+ Eol = Str.find (' \n ' );
71+ }
72+ if (!Str.empty ())
73+ writeWithPrefix (Str);
5374 }
54- ~LogWithNewline () { os << ' \n ' ; }
55- template <typename T> raw_ostream &operator <<(const T &t) && {
56- return os << t;
75+ void emitPrefix () { Os.write (Prefix.c_str (), Prefix.size ()); }
76+ void writeWithPrefix (StringRef Str) {
77+ if (HasPendingNewline) {
78+ emitPrefix ();
79+ HasPendingNewline = false ;
80+ }
81+ Os.write (Str.data (), Str.size ());
5782 }
5883
59- // Prevent copying, as this class manages newline responsibility and is
60- // intended for use as a temporary.
61- LogWithNewline (const LogWithNewline &) = delete ;
62- LogWithNewline &operator =(const LogWithNewline &) = delete ;
63- LogWithNewline &operator =(LogWithNewline &&) = delete ;
64- static constexpr const char *getShortFileName (const char *path) {
65- // Remove the path prefix from the file name.
66- const char *filename = path;
67- for (const char *p = path; *p != ' \0 ' ; ++p) {
68- if (*p == ' /' || *p == ' \\ ' ) {
69- filename = p + 1 ;
70- }
84+ public:
85+ explicit raw_ldbg_ostream (std::string Prefix, raw_ostream &Os)
86+ : Prefix(std::move(Prefix)), Os(Os) {
87+ SetUnbuffered ();
88+ }
89+ ~raw_ldbg_ostream () final {
90+ flushEol ();
91+ Os << ' \n ' ;
92+ }
93+ void flushEol () {
94+ if (HasPendingNewline) {
95+ emitPrefix ();
96+ HasPendingNewline = false ;
7197 }
72- return filename;
7398 }
7499
75- private:
76- raw_ostream &os;
100+ // / Forward the current_pos method to the underlying stream.
101+ uint64_t current_pos () const final { return Os.tell (); }
102+
103+ // / Some of the `<<` operators expect an lvalue, so we trick the type system.
104+ raw_ldbg_ostream &asLvalue () { return *this ; }
77105};
106+
107+ // / Remove the path prefix from the file name.
108+ static LLVM_ATTRIBUTE_UNUSED constexpr const char *
109+ getShortFileName (const char *path) {
110+ const char *filename = path;
111+ for (const char *p = path; *p != ' \0 ' ; ++p) {
112+ if (*p == ' /' || *p == ' \\ ' )
113+ filename = p + 1 ;
114+ }
115+ return filename;
116+ }
117+
118+ // / Compute the prefix for the debug log in the form of:
119+ // / "[DebugType] File:Line "
120+ // / Where the File is the file name without the path prefix.
121+ static LLVM_ATTRIBUTE_UNUSED std::string
122+ computePrefix (const char *DebugType, const char *File, int Line) {
123+ std::string Prefix;
124+ raw_string_ostream OsPrefix (Prefix);
125+ if (DebugType)
126+ OsPrefix << " [" << DebugType << " ] " ;
127+ OsPrefix << File << " :" << Line << " " ;
128+ return OsPrefix.str ();
129+ }
78130} // end namespace impl
79131#else
80132// As others in Debug, When compiling without assertions, the -debug-* options
0 commit comments