bump product version to 5.0.4.1
[LibreOffice.git] / slideshow / source / inc / listenercontainer.hxx
blob2b7ae49b4eaa4af4628955ecb9246105034ade2f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
19 #ifndef INCLUDED_SLIDESHOW_SOURCE_INC_LISTENERCONTAINER_HXX
20 #define INCLUDED_SLIDESHOW_SOURCE_INC_LISTENERCONTAINER_HXX
22 #include <osl/mutex.hxx>
23 #include <boost/utility.hpp>
24 #include <algorithm>
25 #include <vector>
27 namespace slideshow {
28 namespace internal {
30 struct EmptyBase
32 struct EmptyGuard{ explicit EmptyGuard(EmptyBase) {} };
33 struct EmptyClearableGuard
35 explicit EmptyClearableGuard(EmptyBase) {}
36 static void clear() {}
37 static void reset() {}
40 typedef EmptyGuard Guard;
41 typedef EmptyClearableGuard ClearableGuard;
44 class MutexBase
46 public:
47 struct Guard : public osl::MutexGuard
49 explicit Guard(MutexBase const& rBase) :
50 osl::MutexGuard(rBase.maMutex)
53 struct ClearableGuard : public osl::ClearableMutexGuard
55 explicit ClearableGuard(MutexBase const& rBase) :
56 osl::ClearableMutexGuard(rBase.maMutex)
60 mutable osl::Mutex maMutex;
63 template< typename result_type, typename ListenerTargetT > struct FunctionApply
65 template<typename FuncT> static bool apply(
66 FuncT func,
67 ListenerTargetT const& rArg )
69 return func(rArg);
73 template<typename ListenerTargetT> struct FunctionApply<void,ListenerTargetT>
75 template<typename FuncT> static bool apply(
76 FuncT func,
77 ListenerTargetT const& rArg )
79 func(rArg);
80 return true;
84 template< typename ListenerT > struct ListenerOperations
86 /// Notify a single one of the listeners
87 template< typename ContainerT,
88 typename FuncT >
89 static bool notifySingleListener( ContainerT& rContainer,
90 FuncT func )
92 // true: a handler in this queue processed the event
93 // false: no handler in this queue finally processed the event
94 return std::any_of( rContainer.begin(),
95 rContainer.end(),
96 func );
99 /// Notify all listeners
100 template< typename ContainerT,
101 typename FuncT >
102 static bool notifyAllListeners( ContainerT& rContainer,
103 FuncT func )
105 bool bRet(false);
106 typename ContainerT::const_iterator aCurr( rContainer.begin() );
107 typename ContainerT::const_iterator const aEnd ( rContainer.end() );
108 while( aCurr != aEnd )
110 if( FunctionApply< typename FuncT::result_type,
111 typename ContainerT::value_type >::apply(
112 func,
113 *aCurr) )
115 bRet = true;
118 ++aCurr;
121 // true: at least one handler returned true
122 // false: not a single handler returned true
123 return bRet;
126 /// Prune container from deceased listeners
127 template< typename ContainerT >
128 static void pruneListeners( ContainerT&, size_t )
133 template< typename ListenerTargetT >
134 struct ListenerOperations< boost::weak_ptr<ListenerTargetT> >
136 template< typename ContainerT,
137 typename FuncT >
138 static bool notifySingleListener( ContainerT& rContainer,
139 FuncT func )
141 typename ContainerT::const_iterator aCurr( rContainer.begin() );
142 typename ContainerT::const_iterator const aEnd ( rContainer.end() );
143 while( aCurr != aEnd )
145 boost::shared_ptr<ListenerTargetT> pListener( aCurr->lock() );
147 if( pListener && func(pListener) )
148 return true;
150 ++aCurr;
153 return false;
156 template< typename ContainerT,
157 typename FuncT >
158 static bool notifyAllListeners( ContainerT& rContainer,
159 FuncT func )
161 bool bRet(false);
162 typename ContainerT::const_iterator aCurr( rContainer.begin() );
163 typename ContainerT::const_iterator const aEnd ( rContainer.end() );
164 while( aCurr != aEnd )
166 boost::shared_ptr<ListenerTargetT> pListener( aCurr->lock() );
168 if( pListener.get() &&
169 FunctionApply< typename FuncT::result_type,
170 boost::shared_ptr<ListenerTargetT> >::apply(func,pListener) )
172 bRet = true;
175 ++aCurr;
178 return bRet;
180 template< typename ContainerT >
181 static void pruneListeners( ContainerT& rContainer,
182 size_t nSizeThreshold )
184 if( rContainer.size() <= nSizeThreshold )
185 return;
187 ContainerT aAliveListeners;
188 aAliveListeners.reserve(rContainer.size());
190 typename ContainerT::const_iterator aCurr( rContainer.begin() );
191 typename ContainerT::const_iterator const aEnd ( rContainer.end() );
192 while( aCurr != aEnd )
194 if( !aCurr->expired() )
195 aAliveListeners.push_back( *aCurr );
197 ++aCurr;
200 std::swap( rContainer, aAliveListeners );
204 /** Container for objects that can be notified.
206 This templatized container holds listener objects, than can get
207 notified (by calling certain methods on them).
209 @tpl Listener
210 Type for the listener objects to be held
212 @tpl ContainerT
213 Full type of the container to store the listener objects. Defaults
214 to std::vector<ListenerT>
216 @tpl MaxDeceasedListenerUllage
217 Threshold, from which upwards the listener container gets
218 pruned. Avoids frequent copying of nearly empty containers.
220 @attention internal class, not to be used. functionality is
221 incomplete, please use the Thread(Un)safeListenerContainer types
222 from below
224 template< typename ListenerT,
225 typename MutexHolderBaseT,
226 typename ContainerT=std::vector<ListenerT>,
227 size_t MaxDeceasedListenerUllage=16 > class ListenerContainerBase : public MutexHolderBaseT
229 typedef typename MutexHolderBaseT::Guard Guard;
230 typedef typename MutexHolderBaseT::ClearableGuard ClearableGuard;
232 public:
233 typedef ListenerT listener_type;
234 typedef ContainerT container_type;
235 typedef MutexHolderBaseT mutex_type;
237 /** Check whether listener container is empty
239 @return true, if currently no listeners registered. Note that
240 in a multi-threaded scenario, without external synchronisation
241 to this object, the return value might become wrong at any time.
243 bool isEmpty() const
245 Guard aGuard(*this);
246 return maListeners.empty();
249 /** Check whether given listener is already added
251 @return true, if given listener is already added.
253 bool isAdded( listener_type const& rListener ) const
255 Guard aGuard(*this);
257 const typename container_type::const_iterator aEnd( maListeners.end() );
258 if( std::find( maListeners.begin(),
259 aEnd,
260 rListener ) != aEnd )
262 return true; // already added
265 return false;
268 /** Add new listener
270 @param rListener
271 Listener to add
273 @return false, if the listener is already added, true
274 otherwise
276 bool add( listener_type const& rListener )
278 Guard aGuard(*this);
280 // ensure uniqueness
281 if( isAdded(rListener) )
282 return false; // already added
284 maListeners.push_back( rListener );
286 ListenerOperations<ListenerT>::pruneListeners(
287 maListeners,
288 MaxDeceasedListenerUllage);
290 return true;
293 /** Add new listener into sorted container
295 The stored listeners are kept sorted (using this method
296 requires listener_type to have operator< defined on it). Make
297 sure to call addSorted() for <em>each</em> listener to add to
298 this container - sorting is performed under the assumption
299 that existing entries are already sorted.
301 @param rListener
302 Listener to add
304 @return false, if the listener is already added, true
305 otherwise
307 bool addSorted( listener_type const& rListener )
309 Guard aGuard(*this);
311 // ensure uniqueness
312 if( isAdded(rListener) )
313 return false; // already added
315 maListeners.push_back( rListener );
317 // a single entry does not need to be sorted
318 if( maListeners.size() > 1 )
320 std::inplace_merge(
321 maListeners.begin(),
322 boost::prior(maListeners.end()),
323 maListeners.end() );
326 ListenerOperations<ListenerT>::pruneListeners(
327 maListeners,
328 MaxDeceasedListenerUllage);
330 return true;
333 /** Remove listener from container
335 @param rListener
336 The listener to remove
338 @return false, if listener not found in container, true
339 otherwise
341 bool remove( listener_type const& rListener )
343 Guard aGuard(*this);
345 const typename container_type::iterator aEnd( maListeners.end() );
346 typename container_type::iterator aIter;
347 if( (aIter=std::remove(maListeners.begin(),
348 aEnd,
349 rListener)) == aEnd )
351 return false; // listener not found
354 maListeners.erase( aIter, aEnd );
356 return true;
359 /// Removes all listeners in one go
360 void clear()
362 Guard aGuard(*this);
364 maListeners.clear();
367 /** Apply functor to one listener
369 This method applies functor to one of the listeners. Starting
370 with the first entry of the container, the functor is called
371 with the listener entries, until it returns true.
373 @param func
374 Given functor is called with listeners, until it returns true
376 @return true, if functor was successfully applied to a
377 listener
379 template< typename FuncT > bool apply( FuncT func ) const
381 ClearableGuard aGuard(*this);
383 // generate a local copy of all handlers, to make method
384 // reentrant and thread-safe.
385 container_type const local( maListeners );
386 aGuard.clear();
388 const bool bRet(
389 ListenerOperations<ListenerT>::notifySingleListener(
390 local,
391 func ));
394 Guard aGuard2(*this);
395 ListenerOperations<ListenerT>::pruneListeners(
396 const_cast<container_type&>(maListeners),
397 MaxDeceasedListenerUllage);
400 return bRet;
403 /** Apply functor to all listeners
405 This method applies functor to all of the listeners. Starting
406 with the first entry of the container, the functor is called
407 with the listener entries.
409 @param func
410 Given functor is called with listeners.
412 @return true, if functor was successfully applied to at least
413 one listener
415 template< typename FuncT > bool applyAll( FuncT func ) const
417 ClearableGuard aGuard(*this);
419 // generate a local copy of all handlers, to make method
420 // reentrant and thread-safe.
421 container_type const local( maListeners );
422 aGuard.clear();
424 const bool bRet(
425 ListenerOperations<ListenerT>::notifyAllListeners(
426 local,
427 func ));
430 Guard aGuard2(*this);
431 ListenerOperations<ListenerT>::pruneListeners(
432 const_cast<container_type&>(maListeners),
433 MaxDeceasedListenerUllage);
436 return bRet;
439 private:
440 ContainerT maListeners;
445 /** ListenerContainer variant that serialized access
447 This ListenerContainer is safe to use in a multi-threaded
448 context. It serializes access to the object, and avoids
449 dead-locking by releasing the object mutex before calling
450 listeners.
452 template< typename ListenerT,
453 typename ContainerT=std::vector<ListenerT> >
454 class ThreadSafeListenerContainer : public ListenerContainerBase<ListenerT,
455 MutexBase,
456 ContainerT>
462 /** ListenerContainer variant that does not serialize access
464 This ListenerContainer version is not safe to use in a
465 multi-threaded scenario, but has less overhead.
467 template< typename ListenerT,
468 typename ContainerT=std::vector<ListenerT> >
469 class ThreadUnsafeListenerContainer : public ListenerContainerBase<ListenerT,
470 EmptyBase,
471 ContainerT>
475 } // namespace internal
476 } // namespace slideshow
478 #endif // INCLUDED_SLIDESHOW_SOURCE_INC_LISTENERCONTAINER_HXX
480 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */