Bump version to 6.0-36
[LibreOffice.git] / slideshow / source / inc / listenercontainer.hxx
blobe99daf567c8dd53926246ad2b2970270ab5c7518
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 <algorithm>
24 #include <vector>
25 #include <iterator>
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() {}
39 typedef EmptyGuard Guard;
40 typedef EmptyClearableGuard ClearableGuard;
43 template< typename result_type, typename ListenerTargetT > struct FunctionApply
45 template<typename FuncT> static bool apply(
46 FuncT func,
47 ListenerTargetT const& rArg )
49 return func(rArg);
53 template<typename ListenerTargetT> struct FunctionApply<void,ListenerTargetT>
55 template<typename FuncT> static bool apply(
56 FuncT func,
57 ListenerTargetT const& rArg )
59 func(rArg);
60 return true;
64 template< typename ListenerT > struct ListenerOperations
66 /// Notify a single one of the listeners
67 template< typename ContainerT,
68 typename FuncT >
69 static bool notifySingleListener( ContainerT& rContainer,
70 FuncT func )
72 // true: a handler in this queue processed the event
73 // false: no handler in this queue finally processed the event
74 return std::any_of( rContainer.begin(),
75 rContainer.end(),
76 func );
79 /// Notify all listeners
80 template< typename ContainerT,
81 typename FuncT >
82 static bool notifyAllListeners( ContainerT& rContainer,
83 FuncT func )
85 bool bRet(false);
86 for( const auto& rCurr : rContainer )
88 if( FunctionApply< typename ::std::result_of< FuncT( const typename ContainerT::value_type& ) >::type,
89 typename ContainerT::value_type >::apply(
90 func,
91 rCurr) )
93 bRet = true;
97 // true: at least one handler returned true
98 // false: not a single handler returned true
99 return bRet;
102 /// Prune container from deceased listeners
103 template< typename ContainerT >
104 static void pruneListeners( ContainerT&, size_t )
109 template< typename ListenerTargetT >
110 struct ListenerOperations< std::weak_ptr<ListenerTargetT> >
112 template< typename ContainerT,
113 typename FuncT >
114 static bool notifySingleListener( ContainerT& rContainer,
115 FuncT func )
117 for( const auto& rCurr : rContainer )
119 std::shared_ptr<ListenerTargetT> pListener( rCurr.lock() );
121 if( pListener && func(pListener) )
122 return true;
125 return false;
128 template< typename ContainerT,
129 typename FuncT >
130 static bool notifyAllListeners( ContainerT& rContainer,
131 FuncT func )
133 bool bRet(false);
134 for( const auto& rCurr : rContainer )
136 std::shared_ptr<ListenerTargetT> pListener( rCurr.lock() );
138 if( pListener.get() &&
139 FunctionApply<typename ::std::result_of<FuncT (std::shared_ptr<ListenerTargetT> const&)>::type,
140 std::shared_ptr<ListenerTargetT> >::apply(func,pListener) )
142 bRet = true;
146 return bRet;
148 template< typename ContainerT >
149 static void pruneListeners( ContainerT& rContainer,
150 size_t nSizeThreshold )
152 if( rContainer.size() <= nSizeThreshold )
153 return;
155 ContainerT aAliveListeners;
156 aAliveListeners.reserve(rContainer.size());
158 for( const auto& rCurr : rContainer )
160 if( !rCurr.expired() )
161 aAliveListeners.push_back( rCurr );
164 std::swap( rContainer, aAliveListeners );
168 /** Container for objects that can be notified.
170 This templatized container holds listener objects, than can get
171 notified (by calling certain methods on them).
173 @tpl Listener
174 Type for the listener objects to be held
176 @tpl ContainerT
177 Full type of the container to store the listener objects. Defaults
178 to std::vector<ListenerT>
180 @tpl MaxDeceasedListenerUllage
181 Threshold, from which upwards the listener container gets
182 pruned. Avoids frequent copying of nearly empty containers.
184 @attention internal class, not to be used. functionality is
185 incomplete, please use the Thread(Un)safeListenerContainer types
186 from below
188 template< typename ListenerT,
189 typename MutexHolderBaseT,
190 typename ContainerT=std::vector<ListenerT>,
191 size_t MaxDeceasedListenerUllage=16 > class ListenerContainerBase : public MutexHolderBaseT
193 typedef typename MutexHolderBaseT::Guard Guard;
194 typedef typename MutexHolderBaseT::ClearableGuard ClearableGuard;
196 public:
197 typedef ListenerT listener_type;
198 typedef ContainerT container_type;
199 typedef MutexHolderBaseT mutex_type;
201 /** Check whether listener container is empty
203 @return true, if currently no listeners registered. Note that
204 in a multi-threaded scenario, without external synchronisation
205 to this object, the return value might become wrong at any time.
207 bool isEmpty() const
209 Guard aGuard(*this);
210 return maListeners.empty();
213 /** Check whether given listener is already added
215 @return true, if given listener is already added.
217 bool isAdded( listener_type const& rListener ) const
219 Guard aGuard(*this);
221 const typename container_type::const_iterator aEnd( maListeners.end() );
222 if( std::find( maListeners.begin(),
223 aEnd,
224 rListener ) != aEnd )
226 return true; // already added
229 return false;
232 /** Add new listener
234 @param rListener
235 Listener to add
237 void add( listener_type const& rListener )
239 Guard aGuard(*this);
241 // ensure uniqueness
242 if( isAdded(rListener) )
243 return; // already added
245 maListeners.push_back( rListener );
247 ListenerOperations<ListenerT>::pruneListeners(
248 maListeners,
249 MaxDeceasedListenerUllage);
252 /** Add new listener into sorted container
254 The stored listeners are kept sorted (using this method
255 requires listener_type to have operator< defined on it). Make
256 sure to call addSorted() for <em>each</em> listener to add to
257 this container - sorting is performed under the assumption
258 that existing entries are already sorted.
260 @param rListener
261 Listener to add
263 @return false, if the listener is already added, true
264 otherwise
266 bool addSorted( listener_type const& rListener )
268 Guard aGuard(*this);
270 // ensure uniqueness
271 if( isAdded(rListener) )
272 return false; // already added
274 maListeners.push_back( rListener );
276 // a single entry does not need to be sorted
277 if( maListeners.size() > 1 )
279 std::inplace_merge(
280 maListeners.begin(),
281 std::prev(maListeners.end()),
282 maListeners.end() );
285 ListenerOperations<ListenerT>::pruneListeners(
286 maListeners,
287 MaxDeceasedListenerUllage);
289 return true;
292 /** Remove listener from container
294 @param rListener
295 The listener to remove
297 @return false, if listener not found in container, true
298 otherwise
300 bool remove( listener_type const& rListener )
302 Guard aGuard(*this);
304 const typename container_type::iterator aEnd( maListeners.end() );
305 typename container_type::iterator aIter;
306 if( (aIter=std::remove(maListeners.begin(),
307 aEnd,
308 rListener)) == aEnd )
310 return false; // listener not found
313 maListeners.erase( aIter, aEnd );
315 return true;
318 /// Removes all listeners in one go
319 void clear()
321 Guard aGuard(*this);
323 maListeners.clear();
326 /** Apply functor to one listener
328 This method applies functor to one of the listeners. Starting
329 with the first entry of the container, the functor is called
330 with the listener entries, until it returns true.
332 @param func
333 Given functor is called with listeners, until it returns true
335 @return true, if functor was successfully applied to a
336 listener
338 template< typename FuncT > bool apply( FuncT func ) const
340 ClearableGuard aGuard(*this);
342 // generate a local copy of all handlers, to make method
343 // reentrant and thread-safe.
344 container_type const local( maListeners );
345 aGuard.clear();
347 const bool bRet(
348 ListenerOperations<ListenerT>::notifySingleListener(
349 local,
350 func ));
353 Guard aGuard2(*this);
354 ListenerOperations<ListenerT>::pruneListeners(
355 const_cast<container_type&>(maListeners),
356 MaxDeceasedListenerUllage);
359 return bRet;
362 /** Apply functor to all listeners
364 This method applies functor to all of the listeners. Starting
365 with the first entry of the container, the functor is called
366 with the listener entries.
368 @param func
369 Given functor is called with listeners.
371 @return true, if functor was successfully applied to at least
372 one listener
374 template< typename FuncT > bool applyAll( FuncT func ) const
376 ClearableGuard aGuard(*this);
378 // generate a local copy of all handlers, to make method
379 // reentrant and thread-safe.
380 container_type const local( maListeners );
381 aGuard.clear();
383 const bool bRet(
384 ListenerOperations<ListenerT>::notifyAllListeners(
385 local,
386 func ));
389 Guard aGuard2(*this);
390 ListenerOperations<ListenerT>::pruneListeners(
391 const_cast<container_type&>(maListeners),
392 MaxDeceasedListenerUllage);
395 return bRet;
398 private:
399 ContainerT maListeners;
403 /** ListenerContainer variant that does not serialize access
405 This ListenerContainer version is not safe to use in a
406 multi-threaded scenario, but has less overhead.
408 template< typename ListenerT,
409 typename ContainerT=std::vector<ListenerT> >
410 class ThreadUnsafeListenerContainer : public ListenerContainerBase<ListenerT,
411 EmptyBase,
412 ContainerT>
416 } // namespace internal
417 } // namespace slideshow
419 #endif // INCLUDED_SLIDESHOW_SOURCE_INC_LISTENERCONTAINER_HXX
421 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */