Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
5 : : * This Source Code Form is subject to the terms of the Mozilla Public
6 : : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
11 : : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : : * contributor license agreements. See the NOTICE file distributed
13 : : * with this work for additional information regarding copyright
14 : : * ownership. The ASF licenses this file to you under the Apache
15 : : * License, Version 2.0 (the "License"); you may not use this file
16 : : * except in compliance with the License. You may obtain a copy of
17 : : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : : */
19 : : #ifndef INCLUDED_SLIDESHOW_LISTENERCONTAINER_HXX
20 : : #define INCLUDED_SLIDESHOW_LISTENERCONTAINER_HXX
21 : :
22 : : #include <osl/mutex.hxx>
23 : : #include <boost/utility.hpp>
24 : : #include <algorithm>
25 : : #include <vector>
26 : :
27 : : #include "listenercontainerimpl.hxx"
28 : :
29 : : namespace slideshow {
30 : : namespace internal {
31 : :
32 : : /** Container for objects that can be notified.
33 : :
34 : : This templatized container holds listener objects, than can get
35 : : notified (by calling certain methods on them).
36 : :
37 : : @tpl Listener
38 : : Type for the listener objects to be held
39 : :
40 : : @tpl ContainerT
41 : : Full type of the container to store the listener objects. Defaults
42 : : to std::vector<ListenerT>
43 : :
44 : : @tpl MaxDeceasedListenerUllage
45 : : Threshold, from which upwards the listener container gets
46 : : pruned. Avoids frequent copying of nearly empty containers.
47 : :
48 : : @attention internal class, not to be used. functionality is
49 : : incomplete, please use the Thread(Un)safeListenerContainer types
50 : : from below
51 : : */
52 : : template< typename ListenerT,
53 : : typename MutexHolderBaseT,
54 : : typename ContainerT=std::vector<ListenerT>,
55 : 0 : size_t MaxDeceasedListenerUllage=16 > class ListenerContainerBase : public MutexHolderBaseT
56 : : {
57 : : typedef typename MutexHolderBaseT::Guard Guard;
58 : : typedef typename MutexHolderBaseT::ClearableGuard ClearableGuard;
59 : :
60 : : public:
61 : : typedef ListenerT listener_type;
62 : : typedef ContainerT container_type;
63 : : typedef MutexHolderBaseT mutex_type;
64 : :
65 : : /** Check whether listener container is empty
66 : :
67 : : @return true, if currently no listeners registered. Note that
68 : : in a multi-threaded scenario, without external synchronisation
69 : : to this object, the return value might become wrong at any time.
70 : : */
71 : 0 : bool isEmpty() const
72 : : {
73 : 0 : Guard aGuard(*this);
74 : 0 : return maListeners.empty();
75 : : }
76 : :
77 : : /** Check whether given listener is already added
78 : :
79 : : @return true, if given listener is already added.
80 : : */
81 : 0 : bool isAdded( listener_type const& rListener ) const
82 : : {
83 : 0 : Guard aGuard(*this);
84 : :
85 : 0 : const typename container_type::const_iterator aEnd( maListeners.end() );
86 : 0 : if( std::find( maListeners.begin(),
87 : : aEnd,
88 : : rListener ) != aEnd )
89 : : {
90 : 0 : return true; // already added
91 : : }
92 : :
93 : 0 : return false;
94 : : }
95 : :
96 : : /** Add new listener
97 : :
98 : : @param rListener
99 : : Listener to add
100 : :
101 : : @return false, if the listener is already added, true
102 : : otherwise
103 : : */
104 : 0 : bool add( listener_type const& rListener )
105 : : {
106 : 0 : Guard aGuard(*this);
107 : :
108 : : // ensure uniqueness
109 : 0 : if( isAdded(rListener) )
110 : 0 : return false; // already added
111 : :
112 : 0 : maListeners.push_back( rListener );
113 : :
114 : 0 : ListenerOperations<ListenerT>::pruneListeners(
115 : : maListeners,
116 : : MaxDeceasedListenerUllage);
117 : :
118 : 0 : return true;
119 : : }
120 : :
121 : : /** Add new listener into sorted container
122 : :
123 : : The stored listeners are kept sorted (using this method
124 : : requires listener_type to have operator< defined on it). Make
125 : : sure to call addSorted() for <em>each</em> listener to add to
126 : : this container - sorting is performed under the assumption
127 : : that existing entries are already sorted.
128 : :
129 : : @param rListener
130 : : Listener to add
131 : :
132 : : @return false, if the listener is already added, true
133 : : otherwise
134 : : */
135 : 0 : bool addSorted( listener_type const& rListener )
136 : : {
137 : 0 : Guard aGuard(*this);
138 : :
139 : : // ensure uniqueness
140 : 0 : if( isAdded(rListener) )
141 : 0 : return false; // already added
142 : :
143 : 0 : maListeners.push_back( rListener );
144 : :
145 : : // a single entry does not need to be sorted
146 : 0 : if( maListeners.size() > 1 )
147 : : {
148 : 0 : std::inplace_merge(
149 : : maListeners.begin(),
150 : : boost::prior(maListeners.end()),
151 : : maListeners.end() );
152 : : }
153 : :
154 : 0 : ListenerOperations<ListenerT>::pruneListeners(
155 : : maListeners,
156 : : MaxDeceasedListenerUllage);
157 : :
158 : 0 : return true;
159 : : }
160 : :
161 : : /** Remove listener from container
162 : :
163 : : @param rListener
164 : : The listener to remove
165 : :
166 : : @return false, if listener not found in container, true
167 : : otherwise
168 : : */
169 : 0 : bool remove( listener_type const& rListener )
170 : : {
171 : 0 : Guard aGuard(*this);
172 : :
173 : 0 : const typename container_type::iterator aEnd( maListeners.end() );
174 : 0 : typename container_type::iterator aIter;
175 : 0 : if( (aIter=std::remove(maListeners.begin(),
176 : : aEnd,
177 : : rListener)) == aEnd )
178 : : {
179 : 0 : return false; // listener not found
180 : : }
181 : :
182 : 0 : maListeners.erase( aIter, aEnd );
183 : :
184 : 0 : return true;
185 : : }
186 : :
187 : : /// Removes all listeners in one go
188 : 0 : void clear()
189 : : {
190 : 0 : Guard aGuard(*this);
191 : :
192 : 0 : maListeners.clear();
193 : 0 : }
194 : :
195 : : /** Apply functor to one listener
196 : :
197 : : This method applies functor to one of the listeners. Starting
198 : : with the first entry of the container, the functor is called
199 : : with the listener entries, until it returns true.
200 : :
201 : : @param func
202 : : Given functor is called with listeners, until it returns true
203 : :
204 : : @return true, if functor was successfully applied to a
205 : : listener
206 : : */
207 : 0 : template< typename FuncT > bool apply( FuncT func ) const
208 : : {
209 : 0 : ClearableGuard aGuard(*this);
210 : :
211 : : // generate a local copy of all handlers, to make method
212 : : // reentrant and thread-safe.
213 : 0 : container_type const local( maListeners );
214 : 0 : aGuard.clear();
215 : :
216 : : const bool bRet(
217 : : ListenerOperations<ListenerT>::notifySingleListener(
218 : : local,
219 : 0 : func ));
220 : :
221 : : {
222 : 0 : Guard aGuard2(*this);
223 : 0 : ListenerOperations<ListenerT>::pruneListeners(
224 : : const_cast<container_type&>(maListeners),
225 : : MaxDeceasedListenerUllage);
226 : : }
227 : :
228 : 0 : return bRet;
229 : : }
230 : :
231 : : /** Apply functor to all listeners
232 : :
233 : : This method applies functor to all of the listeners. Starting
234 : : with the first entry of the container, the functor is called
235 : : with the listener entries.
236 : :
237 : : @param func
238 : : Given functor is called with listeners.
239 : :
240 : : @return true, if functor was successfully applied to at least
241 : : one listener
242 : : */
243 : 0 : template< typename FuncT > bool applyAll( FuncT func ) const
244 : : {
245 : 0 : ClearableGuard aGuard(*this);
246 : :
247 : : // generate a local copy of all handlers, to make method
248 : : // reentrant and thread-safe.
249 : 0 : container_type const local( maListeners );
250 : 0 : aGuard.clear();
251 : :
252 : : const bool bRet(
253 : : ListenerOperations<ListenerT>::notifyAllListeners(
254 : : local,
255 : 0 : func ));
256 : :
257 : : {
258 : 0 : Guard aGuard2(*this);
259 : 0 : ListenerOperations<ListenerT>::pruneListeners(
260 : : const_cast<container_type&>(maListeners),
261 : : MaxDeceasedListenerUllage);
262 : : }
263 : :
264 : 0 : return bRet;
265 : : }
266 : :
267 : : private:
268 : : ContainerT maListeners;
269 : : };
270 : :
271 : : ////////////////////////////////////////////////////////////////////////////
272 : :
273 : : /** ListenerContainer variant that serialized access
274 : :
275 : : This ListenerContainer is safe to use in a multi-threaded
276 : : context. It serializes access to the object, and avoids
277 : : dead-locking by releasing the object mutex before calling
278 : : listeners.
279 : : */
280 : : template< typename ListenerT,
281 : : typename ContainerT=std::vector<ListenerT> >
282 : : class ThreadSafeListenerContainer : public ListenerContainerBase<ListenerT,
283 : : MutexBase,
284 : : ContainerT>
285 : : {
286 : : };
287 : :
288 : : ////////////////////////////////////////////////////////////////////////////
289 : :
290 : : /** ListenerContainer variant that does not serialize access
291 : :
292 : : This ListenerContainer version is not safe to use in a
293 : : multi-threaded scenario, but has less overhead.
294 : : */
295 : : template< typename ListenerT,
296 : : typename ContainerT=std::vector<ListenerT> >
297 : 0 : class ThreadUnsafeListenerContainer : public ListenerContainerBase<ListenerT,
298 : : EmptyBase,
299 : : ContainerT>
300 : : {
301 : : };
302 : :
303 : : } // namespace internal
304 : : } // namespace slideshow
305 : :
306 : : #endif /* INCLUDED_SLIDESHOW_LISTENERCONTAINER_HXX */
307 : :
308 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|