StreamTee.h revision 317027
1//===-- StreamTee.h ------------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef liblldb_StreamTee_h_
11#define liblldb_StreamTee_h_
12
13#include <limits.h>
14
15#include <mutex>
16
17#include "lldb/Utility/Stream.h"
18
19namespace lldb_private {
20
21class StreamTee : public Stream {
22public:
23  StreamTee() : Stream(), m_streams_mutex(), m_streams() {}
24
25  StreamTee(lldb::StreamSP &stream_sp)
26      : Stream(), m_streams_mutex(), m_streams() {
27    // No need to lock mutex during construction
28    if (stream_sp)
29      m_streams.push_back(stream_sp);
30  }
31
32  StreamTee(lldb::StreamSP &stream_sp, lldb::StreamSP &stream_2_sp)
33      : Stream(), m_streams_mutex(), m_streams() {
34    // No need to lock mutex during construction
35    if (stream_sp)
36      m_streams.push_back(stream_sp);
37    if (stream_2_sp)
38      m_streams.push_back(stream_2_sp);
39  }
40
41  StreamTee(const StreamTee &rhs)
42      : Stream(rhs), m_streams_mutex(), m_streams() {
43    // Don't copy until we lock down "rhs"
44    std::lock_guard<std::recursive_mutex> guard(rhs.m_streams_mutex);
45    m_streams = rhs.m_streams;
46  }
47
48  ~StreamTee() override {}
49
50  StreamTee &operator=(const StreamTee &rhs) {
51    if (this != &rhs) {
52      Stream::operator=(rhs);
53      std::lock_guard<std::recursive_mutex> lhs_locker(m_streams_mutex);
54      std::lock_guard<std::recursive_mutex> rhs_locker(rhs.m_streams_mutex);
55      m_streams = rhs.m_streams;
56    }
57    return *this;
58  }
59
60  void Flush() override {
61    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
62    collection::iterator pos, end;
63    for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) {
64      // Allow for our collection to contain NULL streams. This allows
65      // the StreamTee to be used with hard coded indexes for clients
66      // that might want N total streams with only a few that are set
67      // to valid values.
68      Stream *strm = pos->get();
69      if (strm)
70        strm->Flush();
71    }
72  }
73
74  size_t Write(const void *s, size_t length) override {
75    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
76    if (m_streams.empty())
77      return 0;
78
79    size_t min_bytes_written = SIZE_MAX;
80    collection::iterator pos, end;
81    for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) {
82      // Allow for our collection to contain NULL streams. This allows
83      // the StreamTee to be used with hard coded indexes for clients
84      // that might want N total streams with only a few that are set
85      // to valid values.
86      Stream *strm = pos->get();
87      if (strm) {
88        const size_t bytes_written = strm->Write(s, length);
89        if (min_bytes_written > bytes_written)
90          min_bytes_written = bytes_written;
91      }
92    }
93    if (min_bytes_written == SIZE_MAX)
94      return 0;
95    return min_bytes_written;
96  }
97
98  size_t AppendStream(const lldb::StreamSP &stream_sp) {
99    size_t new_idx = m_streams.size();
100    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
101    m_streams.push_back(stream_sp);
102    return new_idx;
103  }
104
105  size_t GetNumStreams() const {
106    size_t result = 0;
107    {
108      std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
109      result = m_streams.size();
110    }
111    return result;
112  }
113
114  lldb::StreamSP GetStreamAtIndex(uint32_t idx) {
115    lldb::StreamSP stream_sp;
116    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
117    if (idx < m_streams.size())
118      stream_sp = m_streams[idx];
119    return stream_sp;
120  }
121
122  void SetStreamAtIndex(uint32_t idx, const lldb::StreamSP &stream_sp) {
123    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
124    // Resize our stream vector as necessary to fit as many streams
125    // as needed. This also allows this class to be used with hard
126    // coded indexes that can be used contain many streams, not all
127    // of which are valid.
128    if (idx >= m_streams.size())
129      m_streams.resize(idx + 1);
130    m_streams[idx] = stream_sp;
131  }
132
133protected:
134  typedef std::vector<lldb::StreamSP> collection;
135  mutable std::recursive_mutex m_streams_mutex;
136  collection m_streams;
137};
138
139} // namespace lldb_private
140
141#endif // liblldb_StreamTee_h_
142