1 //===-- StreamTee.h ------------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef liblldb_StreamTee_h_
10 #define liblldb_StreamTee_h_
16 #include "lldb/Utility/Stream.h"
18 namespace lldb_private {
20 class StreamTee : public Stream {
22 StreamTee() : Stream(), m_streams_mutex(), m_streams() {}
24 StreamTee(lldb::StreamSP &stream_sp)
25 : Stream(), m_streams_mutex(), m_streams() {
26 // No need to lock mutex during construction
28 m_streams.push_back(stream_sp);
31 StreamTee(lldb::StreamSP &stream_sp, lldb::StreamSP &stream_2_sp)
32 : Stream(), m_streams_mutex(), m_streams() {
33 // No need to lock mutex during construction
35 m_streams.push_back(stream_sp);
37 m_streams.push_back(stream_2_sp);
40 StreamTee(const StreamTee &rhs)
41 : Stream(rhs), m_streams_mutex(), m_streams() {
42 // Don't copy until we lock down "rhs"
43 std::lock_guard<std::recursive_mutex> guard(rhs.m_streams_mutex);
44 m_streams = rhs.m_streams;
47 ~StreamTee() override {}
49 StreamTee &operator=(const StreamTee &rhs) {
51 Stream::operator=(rhs);
52 std::lock(m_streams_mutex, rhs.m_streams_mutex);
53 std::lock_guard<std::recursive_mutex> lhs_locker(m_streams_mutex,
55 std::lock_guard<std::recursive_mutex> rhs_locker(rhs.m_streams_mutex,
57 m_streams = rhs.m_streams;
62 void Flush() override {
63 std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
64 collection::iterator pos, end;
65 for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) {
66 // Allow for our collection to contain NULL streams. This allows the
67 // StreamTee to be used with hard coded indexes for clients that might
68 // want N total streams with only a few that are set to valid values.
69 Stream *strm = pos->get();
75 size_t AppendStream(const lldb::StreamSP &stream_sp) {
76 size_t new_idx = m_streams.size();
77 std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
78 m_streams.push_back(stream_sp);
82 size_t GetNumStreams() const {
85 std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
86 result = m_streams.size();
91 lldb::StreamSP GetStreamAtIndex(uint32_t idx) {
92 lldb::StreamSP stream_sp;
93 std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
94 if (idx < m_streams.size())
95 stream_sp = m_streams[idx];
99 void SetStreamAtIndex(uint32_t idx, const lldb::StreamSP &stream_sp) {
100 std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
101 // Resize our stream vector as necessary to fit as many streams as needed.
102 // This also allows this class to be used with hard coded indexes that can
103 // be used contain many streams, not all of which are valid.
104 if (idx >= m_streams.size())
105 m_streams.resize(idx + 1);
106 m_streams[idx] = stream_sp;
110 typedef std::vector<lldb::StreamSP> collection;
111 mutable std::recursive_mutex m_streams_mutex;
112 collection m_streams;
114 size_t WriteImpl(const void *s, size_t length) override {
115 std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
116 if (m_streams.empty())
119 size_t min_bytes_written = SIZE_MAX;
120 collection::iterator pos, end;
121 for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) {
122 // Allow for our collection to contain NULL streams. This allows the
123 // StreamTee to be used with hard coded indexes for clients that might
124 // want N total streams with only a few that are set to valid values.
125 Stream *strm = pos->get();
127 const size_t bytes_written = strm->Write(s, length);
128 if (min_bytes_written > bytes_written)
129 min_bytes_written = bytes_written;
132 if (min_bytes_written == SIZE_MAX)
134 return min_bytes_written;
138 } // namespace lldb_private
140 #endif // liblldb_StreamTee_h_