aboutsummaryrefslogtreecommitdiff
path: root/include/lldb/Core/StreamTee.h
blob: e2a29a37455348c1b037a64654b20118fe509b34 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//===-- StreamTee.h ------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_StreamTee_h_
#define liblldb_StreamTee_h_

#include <limits.h>

#include "lldb/Core/Stream.h"
#include "lldb/Host/Mutex.h"

namespace lldb_private {

class StreamTee : public Stream
{
public:
    StreamTee () :
        Stream (),
        m_streams_mutex (Mutex::eMutexTypeRecursive),
        m_streams ()
    {
    }

    StreamTee (lldb::StreamSP &stream_sp):
        Stream (),
        m_streams_mutex (Mutex::eMutexTypeRecursive),
        m_streams ()
    {
        // No need to lock mutex during construction
        if (stream_sp)
            m_streams.push_back (stream_sp);
    }
    

    StreamTee (lldb::StreamSP &stream_sp, lldb::StreamSP &stream_2_sp) :
        Stream (),
        m_streams_mutex (Mutex::eMutexTypeRecursive),
        m_streams ()
    {
        // No need to lock mutex during construction
        if (stream_sp)
            m_streams.push_back (stream_sp);
        if (stream_2_sp)
            m_streams.push_back (stream_2_sp);
    }
    
    StreamTee (const StreamTee &rhs) :
        Stream (rhs),
        m_streams_mutex (Mutex::eMutexTypeRecursive),
        m_streams() // Don't copy until we lock down "rhs"
    {
        Mutex::Locker locker (rhs.m_streams_mutex);
        m_streams = rhs.m_streams;
    }

    virtual
    ~StreamTee ()
    {
    }

    StreamTee &
    operator = (const StreamTee &rhs)
    {
        if (this != &rhs) {
            Stream::operator=(rhs);
            Mutex::Locker lhs_locker (m_streams_mutex);
            Mutex::Locker rhs_locker (rhs.m_streams_mutex);
            m_streams = rhs.m_streams;            
        }
        return *this;
    }

    virtual void
    Flush ()
    {
        Mutex::Locker locker (m_streams_mutex);
        collection::iterator pos, end;
        for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos)
        {
            // Allow for our collection to contain NULL streams. This allows
            // the StreamTee to be used with hard coded indexes for clients
            // that might want N total streams with only a few that are set
            // to valid values.
            Stream *strm = pos->get();
            if (strm)
                strm->Flush ();
        }
    }

    virtual size_t
    Write (const void *s, size_t length)
    {
        Mutex::Locker locker (m_streams_mutex);
        if (m_streams.empty())
            return 0;
    
        size_t min_bytes_written = SIZE_MAX;
        collection::iterator pos, end;
        for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos)
        {
            // Allow for our collection to contain NULL streams. This allows
            // the StreamTee to be used with hard coded indexes for clients
            // that might want N total streams with only a few that are set
            // to valid values.
            Stream *strm = pos->get();
            if (strm)
            {
                const size_t bytes_written = strm->Write (s, length);
                if (min_bytes_written > bytes_written)
                    min_bytes_written = bytes_written;
            }
        }
        if (min_bytes_written == SIZE_MAX)
            return 0;
        return min_bytes_written;
    }

    size_t
    AppendStream (const lldb::StreamSP &stream_sp)
    {
        size_t new_idx = m_streams.size();
        Mutex::Locker locker (m_streams_mutex);
        m_streams.push_back (stream_sp);
        return new_idx;
    }

    size_t
    GetNumStreams () const
    {
        size_t result = 0;
        {
            Mutex::Locker locker (m_streams_mutex);
            result = m_streams.size();
        }
        return result;
    }

    lldb::StreamSP
    GetStreamAtIndex (uint32_t idx)
    {
        lldb::StreamSP stream_sp;
        Mutex::Locker locker (m_streams_mutex);
        if (idx < m_streams.size())
            stream_sp = m_streams[idx];
        return stream_sp;
    }

    void
    SetStreamAtIndex (uint32_t idx, const lldb::StreamSP& stream_sp)
    {
        Mutex::Locker locker (m_streams_mutex);
        // Resize our stream vector as necessary to fit as many streams
        // as needed. This also allows this class to be used with hard
        // coded indexes that can be used contain many streams, not all
        // of which are valid.
        if (idx >= m_streams.size())
            m_streams.resize(idx + 1);
        m_streams[idx] = stream_sp;
    }
    

protected:
    typedef std::vector<lldb::StreamSP> collection;
    mutable Mutex m_streams_mutex;
    collection m_streams;
};

} // namespace lldb_private
#endif  // #ifndef liblldb_StreamTee_h_