1 // 2 // Copyright 2020 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 #include <iostream> 8 9 #include "compiler/translator/InfoSink.h" 10 11 namespace sh 12 { 13 14 class StringObserver 15 { 16 public: StringObserver(const std::string & needle)17 StringObserver(const std::string &needle) : needle(needle) { ASSERT(!needle.empty()); } 18 observe(char c)19 bool observe(char c) 20 { 21 if (needle[currPos] == c) 22 { 23 ++currPos; 24 if (currPos == needle.size()) 25 { 26 reset(); 27 return true; 28 } 29 } 30 else 31 { 32 reset(); 33 } 34 return false; 35 } 36 getNeedle()37 const std::string &getNeedle() const { return needle; } 38 reset()39 void reset() { currPos = 0; } 40 41 private: 42 std::string needle; 43 size_t currPos = 0; 44 }; 45 46 class DebugSink : angle::NonCopyable 47 { 48 public: 49 friend class EscapedSink; 50 class EscapedSink : angle::NonCopyable 51 { 52 friend class DebugSink; 53 54 private: EscapedSink(DebugSink & owner)55 EscapedSink(DebugSink &owner) : mOwner(owner), mBegin(owner.size()) {} 56 57 public: EscapedSink(EscapedSink && other)58 EscapedSink(EscapedSink &&other) : mOwner(other.mOwner), mBegin(other.mBegin) {} 59 ~EscapedSink()60 ~EscapedSink() 61 { 62 const char *p = mOwner.c_str(); 63 const int end = mOwner.size(); 64 mOwner.onWrite(p + mBegin, p + end); 65 } 66 get()67 TInfoSinkBase &get() { return mOwner.mParent; } 68 69 operator TInfoSinkBase &() { return get(); } 70 71 private: 72 DebugSink &mOwner; 73 const int mBegin; 74 }; 75 76 public: DebugSink(TInfoSinkBase & parent,bool alsoLogToStdout)77 DebugSink(TInfoSinkBase &parent, bool alsoLogToStdout) 78 : mParent(parent), mAlsoLogToStdout(alsoLogToStdout) 79 {} 80 watch(std::string const & needle)81 void watch(std::string const &needle) 82 { 83 if (!needle.empty()) 84 { 85 mObservers.emplace_back(needle); 86 } 87 } 88 erase()89 void erase() 90 { 91 mParent.erase(); 92 for (StringObserver &observer : mObservers) 93 { 94 observer.reset(); 95 } 96 } 97 size()98 int size() { return mParent.size(); } 99 str()100 const TPersistString &str() const { return mParent.str(); } 101 c_str()102 const char *c_str() const { return mParent.c_str(); } 103 escape()104 EscapedSink escape() { return EscapedSink(*this); } 105 106 template <typename T> 107 DebugSink &operator<<(const T &value) 108 { 109 const size_t begin = mParent.size(); 110 mParent << value; 111 const size_t end = mParent.size(); 112 113 const char *p = mParent.c_str(); 114 onWrite(p + begin, p + end); 115 116 return *this; 117 } 118 119 private: onWrite(const char * begin,char const * end)120 void onWrite(const char *begin, char const *end) 121 { 122 const char *p = begin; 123 while (p != end) 124 { 125 if (mAlsoLogToStdout) 126 { 127 std::cout << *p; 128 } 129 130 for (StringObserver &observer : mObservers) 131 { 132 if (observer.observe(*p)) 133 { 134 if (mAlsoLogToStdout) 135 { 136 std::cout.flush(); 137 } 138 const std::string &needle = observer.getNeedle(); 139 (void)needle; 140 ASSERT(true); // place your breakpoint here 141 } 142 } 143 144 ++p; 145 } 146 147 if (mAlsoLogToStdout) 148 { 149 std::cout.flush(); 150 } 151 } 152 153 private: 154 TInfoSinkBase &mParent; 155 std::vector<StringObserver> mObservers; 156 bool mAlsoLogToStdout; 157 }; 158 159 } // namespace sh 160