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