Library of Assembled Shared Sources
proxy_o_stream.cpp
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2018 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43#include "lass_common.h"
44#include "proxy_o_stream.h"
45#include "../util/atomic.h"
46
47
48namespace lass
49{
50
51namespace io
52{
53
54/** Construct a proxy with a destination, and set a filter for it
55 *//*
56ProxyOStream::ProxyOStream()
57{
58 add(&std::cout, acceptAll);
59}
60*/
61/** Construct a proxy with a destination, and set a filter for it
62 */
63ProxyOStream::ProxyOStream( std::ostream* destination, TMask destinationMask )
64{
65 add(destination, destinationMask);
66}
67
68
69
70/** Add a std::ostream to the list of destination streams.
71 * - Proxy stream does NOT take ownership of destination stream, it stays your own.
72 * - If destination stream is already added to proxy, then it's not added again. i.e.
73 * You can safely add the same destination twice, but it will only set the mask.
74 */
75void ProxyOStream::add( std::ostream* destination, TMask destinationMask )
76{
77 TDestinations::iterator i = findStream(destination);
78 if (i != destinations_.end())
79 {
80 i->mask = destinationMask;
81 }
82 else
83 {
84 Destination dest = { destination, destinationMask };
85 destinations_.push_back(dest);
86 }
87}
88
89
90
91/** Remove a std::ostream from the list of destination streams.
92 * - Proxy stream does not deallocate destination stream, it stays your own responsibility.
93 * - If you try to remove a destination that's not there, nothing happens. i.e. it's safe
94 * to remove a stream that the proxy doesn't has.
95 */
96void ProxyOStream::remove( std::ostream* destination )
97{
98 TDestinations::iterator i = findStream(destination);
99 if (i == destinations_.end())
100 {
101 return;
102 }
103 destinations_.erase(i);
104}
105
106
107
108/** Return accept mask on destination stream.
109 * If destination stream does not exists in proxy, it throws an exception.
110 */
111ProxyOStream::TMask ProxyOStream::filter( std::ostream* destination ) const
112{
113 for (TDestinations::const_iterator i = destinations_.begin(), end = destinations_.end(); i != end; ++i)
114 {
115 if (i->stream == destination)
116 {
117 return i->mask;
118 }
119 }
120 LASS_THROW("Cannot return filter because std::ostream '" << destination << "' is not "
121 << "connected to the ProxyOStream '" << this << "' as destination.");
122}
123
124
125
126/** Set filter on destination stream.
127 * If destination stream does not exists, it throws an exception.
128 */
129void ProxyOStream::setFilter( std::ostream* destination, TMask destinationMask)
130{
131 TDestinations::iterator i = findStream(destination);
132 if (i == destinations_.end())
133 {
134 LASS_THROW("Cannot set filter because std::ostream '" << destination << "' is not "
135 << "connected to the ProxyOStream '" << this << "' as destination.");
136 }
137 i->mask = destinationMask;
138}
139
140
141impl::ProxyOStreamLock ProxyOStream::operator()( TMask messageMask )
142{
143 impl::ProxyOStreamLock lock(this, messageMask);
144 return lock;
145}
146
147
148/** ProxyOStreamLock proxy stream for output on 'acceptAll' and distribute the std manipulator.
149* This command will give command to a lock, as if the message mask is acceptAll.
150* This has the same effect as (*this)(acceptAll) << x;
151*/
152impl::ProxyOStreamLock ProxyOStream::operator<< (std::ostream& (*x) (std::ostream&))
153{
154 impl::ProxyOStreamLock result(this, acceptAll);
155 result << x;
156 return result;
157}
158
159
160/** flush all destination streams.
161 */
163{
164 for (TDestinations::iterator i = destinations_.begin(), end = destinations_.end(); i != end; ++i)
165 {
166 i->stream->flush();
167 }
168}
169
170
171ProxyOStream::TDestinations::iterator ProxyOStream::findStream(std::ostream* stream)
172{
173 // We put things in a map with a O(n) search because:
174 // - adding/removing/looking up a destination stream happens rarely
175 // - n is small (often 1)
176 // - iterating over all streams happens frequently, and vectors are bleeding fast for that ...
177 for (TDestinations::iterator i = destinations_.begin(), end = destinations_.end(); i != end; ++i)
178 {
179 if (i->stream == stream)
180 {
181 return i;
182 }
183 }
184 return destinations_.end();
185}
186
187
188// --- Lock ----------------------------------------------------------------------------------------
189
190namespace impl
191{
192
193/** Lock (or don't lock if proxy == 0) a proxy.
194 */
195ProxyOStreamLock::ProxyOStreamLock(ProxyOStream* proxy, ProxyOStream::TMask messageMask):
196 proxy_(proxy),
197 messageMask_(messageMask)
198{
199 if (proxy_)
200 {
201 proxy_->lock_.lock();
202 }
203}
204
205
206
207ProxyOStreamLock::ProxyOStreamLock(ProxyOStreamLock&& other):
208 proxy_(other.proxy_),
209 messageMask_(other.messageMask_)
210{
211 other.proxy_ = 0;
212 other.messageMask_ = 0;
213
214 // this also implicitly transfers the ownership of the semaphore lock.
215 // the other won't unlock it anymore because it not longer has a proxy_.
216}
217
218
219
220/** On the end of the lock, flush the proxy.
221 */
222ProxyOStreamLock::~ProxyOStreamLock()
223{
224 if (proxy_)
225 {
226 proxy_->flush();
227 proxy_->lock_.unlock();
228 }
229}
230
231
232/** distribute std manipulators over all destination streams.
233 * Only distribute input if it's still locking a proxy (i.e. if proxy_ != Null).
234 */
235ProxyOStreamLock& ProxyOStreamLock::operator<<(std::ostream& (*x) (std::ostream&))
236{
237 if (proxy_)
238 {
239 for (ProxyOStream::TDestinations::iterator i = proxy_->destinations_.begin(), end = proxy_->destinations_.end(); i != end; ++i)
240 {
241 if (util::checkMaskedSome(i->mask, messageMask_))
242 {
243 LASS_ENFORCE_STREAM(*(i->stream)) << x;
244 }
245 }
246 }
247 return *this;
248}
249
250
251}
252
253}
254
255}
void add(std::ostream *destination, TMask filterMask=acceptAll)
Add a std::ostream to the list of destination streams.
TMask filter(std::ostream *destination) const
Return accept mask on destination stream.
void flush()
flush all destination streams.
void setFilter(std::ostream *destination, TMask filterMask)
Set filter on destination stream.
ProxyOStream(std::ostream *destination=&std::cout, TMask filterMask=acceptAll)
Construct a proxy with a destination, and set a filter for it.
void remove(std::ostream *destination)
Remove a std::ostream from the list of destination streams.
impl::ProxyOStreamLock operator<<(const T &x)
ProxyOStreamLock proxy stream for output on 'acceptAll' and distribute input.
bool checkMaskedSome(T a_bits, const T &a_mask)
Check the masked bits and return true if at least one is set.
streams, binary streams, vrmlstreams, ...
Library for Assembled Shared Sources.
Definition config.h:53