Phasor  01.00.10.059
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Streams.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <string>
4 #include <sstream>
5 #include <memory>
6 #include <assert.h>
7 #include <list>
8 #include <set>
9 #include "noncopyable.h"
10 #include "Types.h"
11 
12 #define _WINDOWS_LINE_END
13 #ifndef _WINDOWS_LINE_END
14 static const wchar_t NEW_LINE_CHAR = L'\n';
15 #else
16 static const wchar_t* NEW_LINE_CHAR = L"\r\n";
17 #endif
18 
19 struct endl_tag {};
20 static const endl_tag endl;
21 
22 class COutStream : private noncopyable
23 {
24 private:
25  std::wstring str;
26  size_t length_to_write;
27  static const size_t kDefaultBufferSize = 1 << 13; // 8kb
28 
29 protected:
30 
31  // These are the only functions to access str and length_to_write.
32  // Derived classes that need to provide thread safety should override these.
33  virtual void AppendData(const std::wstring& str);
34  virtual void AppendData(wchar_t c);
35  virtual void Reserve(size_t size);
36 
37 public: // stream modifiers
38  bool no_flush;
39  std::set<COutStream*> masters;
40 
41  // masters should be valid for the duration of this stream
42  void Notify(COutStream& master);
43  void DontNotify(COutStream& master);
44 
45 public:
46  COutStream();
47  virtual ~COutStream();
48 
49  // Creates a copy of stream
50  virtual std::unique_ptr<COutStream> clone() const = 0;
51  // Called to write data to the stream
52  virtual bool Write(const std::wstring& str) = 0;
53 
54  // Called to flush the stream (and on endl)
55  void Flush();
56 
57  COutStream & operator<<(const endl_tag&);
58  COutStream & operator<<(const std::string& string);
59  COutStream & operator<<(const std::wstring& string);
60  COutStream & operator<<(const char *string);
61  COutStream & operator<<(const wchar_t *string);
62  COutStream & operator<<(wchar_t c);
63  COutStream & operator<<(DWORD number);
64  COutStream & operator<<(int number);
65  COutStream & operator<<(double number);
66 
67  // Print using c-style functions. endl is appended to each message and
68  // as such the stream is flushed after each call.
69  void print(const char* format, ...);
70  void wprint(const wchar_t* format, ...);
71 };
72 
73 class NoFlush
74 {
75 private:
76  COutStream& stream;
77  bool prev;
78 public:
79  explicit NoFlush(COutStream& stream) : stream(stream),
80  prev(stream.no_flush)
81  {
82  stream.no_flush = true;
83  }
84 
86  {
87  if (!(stream.no_flush = prev)) stream.Flush();
88  }
89 };
90 
92 {
93 private:
94  COutStream& slave, &master;
95 
96 public:
98  : slave(slave), master(master)
99  {
100  slave.Notify(master);
101  }
102 
104  {
105  slave.DontNotify(master);
106  }
107 };
108 
109 // Creates a temporary forwarding chain
110 // No streams are copied and as such this class cannot be copied/cloned
111 // and all streams should remain valid for its duration.
112 class TempForwarder : public COutStream
113 {
114 public:
115  typedef std::unique_ptr<TempForwarder> next_ptr;
116 private:
117  COutStream& stream;
118  next_ptr next;
119 
120 protected:
121  bool Write(const std::wstring& str) override
122  {
123  bool b = true;
124  if (next) b = next->Write(str);
125  return b && stream.Write(str);
126  }
127  // This stream is temporary and shouldn't be copied/cloned.
128  std::unique_ptr<COutStream> clone() const override
129  {
130  assert(0);
131  return std::unique_ptr<COutStream>();
132  }
133 
134 public:
136  : stream(stream), next(std::move(next)) {}
137 
138  static next_ptr end_point(COutStream& stream)
139  {
140  return next_ptr(new TempForwarder(stream, next_ptr()));
141  }
142 
143  static next_ptr mid_point(COutStream& stream, next_ptr& next)
144  {
145  return next_ptr(new TempForwarder(stream, std::move(next)));
146  }
147 };
148 
149 // Used to create a forwarding chain for COutStreams.
150 // All streams passed in are cloned and managed by this class.
151 class Forwarder : public COutStream
152 {
153 protected:
154  bool Write(const std::wstring& str) override
155  {
156  bool b = true;
157  if (next) b = next->Write(str);
158  return b && stream->Write(str);
159  }
160 
161 public:
162  typedef std::unique_ptr<Forwarder> next_ptr;
163  typedef std::unique_ptr<COutStream> stream_ptr;
164 
165  explicit Forwarder(COutStream& stream, next_ptr& next)
166  : stream(stream.clone()), next(std::move(next))
167  {
168  }
169 
170  std::unique_ptr<COutStream> clone() const override
171  {
172  std::unique_ptr<COutStream> forwarder(new Forwarder);
173  const Forwarder* this_next = this;
174  Forwarder* that_next = (Forwarder*)forwarder.get();
175  while (this_next) {
176  that_next->next = next_ptr((Forwarder*)this_next->next->clone().release());
177  that_next->stream = this_next->stream->clone();
178  this_next = this->next->next.get();
179  that_next = that_next->next.get();
180  }
181  return forwarder;
182  }
183 
184  static next_ptr end_point(COutStream& stream)
185  {
186  return next_ptr(new Forwarder(stream, next_ptr()));
187  }
188 
189  static next_ptr mid_point(COutStream& stream, next_ptr& next)
190  {
191  return next_ptr(new Forwarder(stream, std::move(next)));
192  }
193 
194 private:
195  next_ptr next;
196  stream_ptr stream;
197 
198  Forwarder() {}
199 };
200 
201 
202 // ignores all input
203 class SinkStream : public COutStream
204 {
205  virtual bool Write(const std::wstring& str)
206  {
207  return true;
208  }
209 
210 public:
211 
212  virtual std::unique_ptr<COutStream> clone() const override
213  {
214  return std::unique_ptr<COutStream>(new SinkStream());
215  }
216 
217 };
218 
219 class RecordStream : public COutStream
220 {
221 private:
222  std::list<std::wstring> output;
223 
224 protected:
225  virtual bool Write(const std::wstring& str)
226  {
227  if (str.size() != 0) output.push_back(str);
228  return true;
229  }
230 
231 public:
233 
234  const std::list<std::wstring>& getRecord() const {
235  return output;
236  }
237 
238  virtual std::unique_ptr<COutStream> clone() const override
239  {
240  return std::unique_ptr<COutStream>(new RecordStream());
241  }
242 };