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: */
|