Bump version to 6.4-15
[LibreOffice.git] / slideshow / source / inc / listenercontainer.hxx
blobd1f47d78b38a9076820367315046e0be11f0d925
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, then 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;
200 /** Check whether listener container is empty
202 @return true, if currently no listeners registered. Note that
203 in a multi-threaded scenario, without external synchronisation
204 to this object, the return value might become wrong at any time.
206 bool isEmpty() const
208 Guard aGuard(*this);
209 return maListeners.empty();
212 /** Check whether given listener is already added
214 @return true, if given listener is already added.
216 bool isAdded( listener_type const& rListener ) const
218 Guard aGuard(*this);
220 const typename container_type::const_iterator aEnd( maListeners.end() );
221 if( std::find( maListeners.begin(),
222 aEnd,
223 rListener ) != aEnd )
225 return true; // already added
228 return false;
231 /** Add new listener
233 @param rListener
234 Listener to add
236 void add( listener_type const& rListener )
238 Guard aGuard(*this);
240 // ensure uniqueness
241 if( isAdded(rListener) )
242 return; // already added
244 maListeners.push_back( rListener );
246 ListenerOperations<ListenerT>::pruneListeners(
247 maListeners,
248 MaxDeceasedListenerUllage);
251 /** Add new listener into sorted container
253 The stored listeners are kept sorted (using this method
254 requires listener_type to have operator< defined on it). Make
255 sure to call addSorted() for <em>each</em> listener to add to
256 this container - sorting is performed under the assumption
257 that existing entries are already sorted.
259 @param rListener
260 Listener to add
262 @return false, if the listener is already added, true
263 otherwise
265 bool addSorted( listener_type const& rListener )
267 Guard aGuard(*this);
269 // ensure uniqueness
270 if( isAdded(rListener) )
271 return false; // already added
273 maListeners.push_back( rListener );
275 // a single entry does not need to be sorted
276 if( maListeners.size() > 1 )
278 std::inplace_merge(
279 maListeners.begin(),
280 std::prev(maListeners.end()),
281 maListeners.end() );
284 ListenerOperations<ListenerT>::pruneListeners(
285 maListeners,
286 MaxDeceasedListenerUllage);
288 return true;
291 /** Remove listener from container
293 @param rListener
294 The listener to remove
296 @return false, if listener not found in container, true
297 otherwise
299 bool remove( listener_type const& rListener )
301 Guard aGuard(*this);
303 const typename container_type::iterator aEnd( maListeners.end() );
304 typename container_type::iterator aIter;
305 if( (aIter=std::remove(maListeners.begin(),
306 aEnd,
307 rListener)) == aEnd )
309 return false; // listener not found
312 maListeners.erase( aIter, aEnd );
314 return true;
317 /// Removes all listeners in one go
318 void clear()
320 Guard aGuard(*this);
322 maListeners.clear();
325 /** Apply functor to one listener
327 This method applies functor to one of the listeners. Starting
328 with the first entry of the container, the functor is called
329 with the listener entries, until it returns true.
331 @param func
332 Given functor is called with listeners, until it returns true
334 @return true, if functor was successfully applied to a
335 listener
337 template< typename FuncT > bool apply( FuncT func ) const
339 ClearableGuard aGuard(*this);
341 // generate a local copy of all handlers, to make method
342 // reentrant and thread-safe.
343 container_type const local( maListeners );
344 aGuard.clear();
346 const bool bRet(
347 ListenerOperations<ListenerT>::notifySingleListener(
348 local,
349 func ));
352 Guard aGuard2(*this);
353 ListenerOperations<ListenerT>::pruneListeners(
354 const_cast<container_type&>(maListeners),
355 MaxDeceasedListenerUllage);
358 return bRet;
361 /** Apply functor to all listeners
363 This method applies functor to all of the listeners. Starting
364 with the first entry of the container, the functor is called
365 with the listener entries.
367 @param func
368 Given functor is called with listeners.
370 @return true, if functor was successfully applied to at least
371 one listener
373 template< typename FuncT > bool applyAll( FuncT func ) const
375 ClearableGuard aGuard(*this);
377 // generate a local copy of all handlers, to make method
378 // reentrant and thread-safe.
379 container_type const local( maListeners );
380 aGuard.clear();
382 const bool bRet(
383 ListenerOperations<ListenerT>::notifyAllListeners(
384 local,
385 func ));
388 Guard aGuard2(*this);
389 ListenerOperations<ListenerT>::pruneListeners(
390 const_cast<container_type&>(maListeners),
391 MaxDeceasedListenerUllage);
394 return bRet;
397 private:
398 ContainerT maListeners;
402 /** ListenerContainer variant that does not serialize access
404 This ListenerContainer version is not safe to use in a
405 multi-threaded scenario, but has less overhead.
407 template< typename ListenerT,
408 typename ContainerT=std::vector<ListenerT> >
409 class ThreadUnsafeListenerContainer : public ListenerContainerBase<ListenerT,
410 EmptyBase,
411 ContainerT>
415 } // namespace internal
416 } // namespace slideshow
418 #endif // INCLUDED_SLIDESHOW_SOURCE_INC_LISTENERCONTAINER_HXX
420 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */