StreamTee.h revision 341825
1143439Sobrien//===-- StreamTee.h ------------------------------------------*- C++ -*-===//
2143439Sobrien//
3143439Sobrien//                     The LLVM Compiler Infrastructure
4143439Sobrien//
5143439Sobrien// This file is distributed under the University of Illinois Open Source
6143439Sobrien// License. See LICENSE.TXT for details.
7143439Sobrien//
8143439Sobrien//===----------------------------------------------------------------------===//
9143439Sobrien
10143439Sobrien#ifndef liblldb_StreamTee_h_
11143439Sobrien#define liblldb_StreamTee_h_
12143439Sobrien
13143439Sobrien#include <limits.h>
14143439Sobrien
15143439Sobrien#include <mutex>
16143439Sobrien
17143439Sobrien#include "lldb/Utility/Stream.h"
18143439Sobrien
19143439Sobriennamespace lldb_private {
20143439Sobrien
21143439Sobrienclass StreamTee : public Stream {
22143439Sobrienpublic:
23143439Sobrien  StreamTee() : Stream(), m_streams_mutex(), m_streams() {}
24143439Sobrien
25143439Sobrien  StreamTee(lldb::StreamSP &stream_sp)
26143439Sobrien      : Stream(), m_streams_mutex(), m_streams() {
27143439Sobrien    // No need to lock mutex during construction
28143439Sobrien    if (stream_sp)
29143439Sobrien      m_streams.push_back(stream_sp);
30143439Sobrien  }
31143439Sobrien
32143439Sobrien  StreamTee(lldb::StreamSP &stream_sp, lldb::StreamSP &stream_2_sp)
33143439Sobrien      : Stream(), m_streams_mutex(), m_streams() {
34143439Sobrien    // No need to lock mutex during construction
35143439Sobrien    if (stream_sp)
36143439Sobrien      m_streams.push_back(stream_sp);
37143439Sobrien    if (stream_2_sp)
38143439Sobrien      m_streams.push_back(stream_2_sp);
39143439Sobrien  }
40143439Sobrien
41143439Sobrien  StreamTee(const StreamTee &rhs)
42143439Sobrien      : Stream(rhs), m_streams_mutex(), m_streams() {
43143439Sobrien    // Don't copy until we lock down "rhs"
44143439Sobrien    std::lock_guard<std::recursive_mutex> guard(rhs.m_streams_mutex);
45143439Sobrien    m_streams = rhs.m_streams;
46143439Sobrien  }
47143439Sobrien
48143439Sobrien  ~StreamTee() override {}
49143439Sobrien
50143439Sobrien  StreamTee &operator=(const StreamTee &rhs) {
51143439Sobrien    if (this != &rhs) {
52143439Sobrien      Stream::operator=(rhs);
53143439Sobrien      std::lock_guard<std::recursive_mutex> lhs_locker(m_streams_mutex);
54143439Sobrien      std::lock_guard<std::recursive_mutex> rhs_locker(rhs.m_streams_mutex);
55143439Sobrien      m_streams = rhs.m_streams;
56143439Sobrien    }
57143439Sobrien    return *this;
58143439Sobrien  }
59143439Sobrien
60143439Sobrien  void Flush() override {
61143439Sobrien    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
62143439Sobrien    collection::iterator pos, end;
63143439Sobrien    for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) {
64143439Sobrien      // Allow for our collection to contain NULL streams. This allows the
65143439Sobrien      // StreamTee to be used with hard coded indexes for clients that might
66143439Sobrien      // want N total streams with only a few that are set to valid values.
67143439Sobrien      Stream *strm = pos->get();
68143439Sobrien      if (strm)
69143439Sobrien        strm->Flush();
70143439Sobrien    }
71143439Sobrien  }
72143439Sobrien
73143439Sobrien  size_t Write(const void *s, size_t length) override {
74143439Sobrien    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
75143439Sobrien    if (m_streams.empty())
76143439Sobrien      return 0;
77143439Sobrien
78143439Sobrien    size_t min_bytes_written = SIZE_MAX;
79143439Sobrien    collection::iterator pos, end;
80143439Sobrien    for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) {
81143439Sobrien      // Allow for our collection to contain NULL streams. This allows the
82143439Sobrien      // StreamTee to be used with hard coded indexes for clients that might
83143439Sobrien      // want N total streams with only a few that are set to valid values.
84143439Sobrien      Stream *strm = pos->get();
85143439Sobrien      if (strm) {
86143439Sobrien        const size_t bytes_written = strm->Write(s, length);
87143439Sobrien        if (min_bytes_written > bytes_written)
88143439Sobrien          min_bytes_written = bytes_written;
89143439Sobrien      }
90143439Sobrien    }
91143439Sobrien    if (min_bytes_written == SIZE_MAX)
92143439Sobrien      return 0;
93143439Sobrien    return min_bytes_written;
94143439Sobrien  }
95143439Sobrien
96143439Sobrien  size_t AppendStream(const lldb::StreamSP &stream_sp) {
97143439Sobrien    size_t new_idx = m_streams.size();
98143439Sobrien    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
99143439Sobrien    m_streams.push_back(stream_sp);
100143439Sobrien    return new_idx;
101143439Sobrien  }
102143439Sobrien
103143439Sobrien  size_t GetNumStreams() const {
104143439Sobrien    size_t result = 0;
105143439Sobrien    {
106143439Sobrien      std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
107143439Sobrien      result = m_streams.size();
108143439Sobrien    }
109143439Sobrien    return result;
110143439Sobrien  }
111143439Sobrien
112143439Sobrien  lldb::StreamSP GetStreamAtIndex(uint32_t idx) {
113143439Sobrien    lldb::StreamSP stream_sp;
114143439Sobrien    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
115143439Sobrien    if (idx < m_streams.size())
116143439Sobrien      stream_sp = m_streams[idx];
117143439Sobrien    return stream_sp;
118143439Sobrien  }
119143439Sobrien
120143439Sobrien  void SetStreamAtIndex(uint32_t idx, const lldb::StreamSP &stream_sp) {
121143439Sobrien    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
122143439Sobrien    // Resize our stream vector as necessary to fit as many streams as needed.
123143439Sobrien    // This also allows this class to be used with hard coded indexes that can
124143439Sobrien    // be used contain many streams, not all of which are valid.
125143439Sobrien    if (idx >= m_streams.size())
126143439Sobrien      m_streams.resize(idx + 1);
127143439Sobrien    m_streams[idx] = stream_sp;
128143439Sobrien  }
129143439Sobrien
130143439Sobrienprotected:
131143439Sobrien  typedef std::vector<lldb::StreamSP> collection;
132143439Sobrien  mutable std::recursive_mutex m_streams_mutex;
133143439Sobrien  collection m_streams;
134143439Sobrien};
135143439Sobrien
136143439Sobrien} // namespace lldb_private
137143439Sobrien
138143439Sobrien#endif // liblldb_StreamTee_h_
139143439Sobrien