StreamTee.h revision 36da2aa6dc5ad9994b638ed09eb81c44cc05540b
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 "lldb/Core/Stream.h"
16#include "lldb/Host/Mutex.h"
17
18namespace lldb_private {
19
20class StreamTee : public Stream
21{
22public:
23    StreamTee () :
24        Stream (),
25        m_streams_mutex (Mutex::eMutexTypeRecursive),
26        m_streams ()
27    {
28    }
29
30    StreamTee (lldb::StreamSP &stream_sp):
31        Stream (),
32        m_streams_mutex (Mutex::eMutexTypeRecursive),
33        m_streams ()
34    {
35        // No need to lock mutex during construction
36        if (stream_sp)
37            m_streams.push_back (stream_sp);
38    }
39
40
41    StreamTee (lldb::StreamSP &stream_sp, lldb::StreamSP &stream_2_sp) :
42        Stream (),
43        m_streams_mutex (Mutex::eMutexTypeRecursive),
44        m_streams ()
45    {
46        // No need to lock mutex during construction
47        if (stream_sp)
48            m_streams.push_back (stream_sp);
49        if (stream_2_sp)
50            m_streams.push_back (stream_2_sp);
51    }
52
53    StreamTee (const StreamTee &rhs) :
54        Stream (rhs),
55        m_streams_mutex (Mutex::eMutexTypeRecursive),
56        m_streams() // Don't copy until we lock down "rhs"
57    {
58        Mutex::Locker locker (rhs.m_streams_mutex);
59        m_streams = rhs.m_streams;
60    }
61
62    virtual
63    ~StreamTee ()
64    {
65    }
66
67    StreamTee &
68    operator = (const StreamTee &rhs)
69    {
70        if (this != &rhs) {
71            Stream::operator=(rhs);
72            Mutex::Locker lhs_locker (m_streams_mutex);
73            Mutex::Locker rhs_locker (rhs.m_streams_mutex);
74            m_streams = rhs.m_streams;
75        }
76        return *this;
77    }
78
79    virtual void
80    Flush ()
81    {
82        Mutex::Locker locker (m_streams_mutex);
83        collection::iterator pos, end;
84        for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos)
85        {
86            // Allow for our collection to contain NULL streams. This allows
87            // the StreamTee to be used with hard coded indexes for clients
88            // that might want N total streams with only a few that are set
89            // to valid values.
90            Stream *strm = pos->get();
91            if (strm)
92                strm->Flush ();
93        }
94    }
95
96    virtual size_t
97    Write (const void *s, size_t length)
98    {
99        Mutex::Locker locker (m_streams_mutex);
100        if (m_streams.empty())
101            return 0;
102
103        size_t min_bytes_written = SIZE_MAX;
104        collection::iterator pos, end;
105        for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos)
106        {
107            // Allow for our collection to contain NULL streams. This allows
108            // the StreamTee to be used with hard coded indexes for clients
109            // that might want N total streams with only a few that are set
110            // to valid values.
111            Stream *strm = pos->get();
112            if (strm)
113            {
114                const size_t bytes_written = strm->Write (s, length);
115                if (min_bytes_written > bytes_written)
116                    min_bytes_written = bytes_written;
117            }
118        }
119        if (min_bytes_written == SIZE_MAX)
120            return 0;
121        return min_bytes_written;
122    }
123
124    size_t
125    AppendStream (const lldb::StreamSP &stream_sp)
126    {
127        size_t new_idx = m_streams.size();
128        Mutex::Locker locker (m_streams_mutex);
129        m_streams.push_back (stream_sp);
130        return new_idx;
131    }
132
133    size_t
134    GetNumStreams () const
135    {
136        size_t result = 0;
137        {
138            Mutex::Locker locker (m_streams_mutex);
139            result = m_streams.size();
140        }
141        return result;
142    }
143
144    lldb::StreamSP
145    GetStreamAtIndex (uint32_t idx)
146    {
147        lldb::StreamSP stream_sp;
148        Mutex::Locker locker (m_streams_mutex);
149        if (idx < m_streams.size())
150            stream_sp = m_streams[idx];
151        return stream_sp;
152    }
153
154    void
155    SetStreamAtIndex (uint32_t idx, const lldb::StreamSP& stream_sp)
156    {
157        Mutex::Locker locker (m_streams_mutex);
158        // Resize our stream vector as necessary to fit as many streams
159        // as needed. This also allows this class to be used with hard
160        // coded indexes that can be used contain many streams, not all
161        // of which are valid.
162        if (idx >= m_streams.size())
163            m_streams.resize(idx + 1);
164        m_streams[idx] = stream_sp;
165    }
166
167
168protected:
169    typedef std::vector<lldb::StreamSP> collection;
170    mutable Mutex m_streams_mutex;
171    collection m_streams;
172};
173
174} // namespace lldb_private
175#endif  // #ifndef liblldb_StreamTee_h_
176