1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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(
47 ListenerTargetT
const& rArg
)
53 template<typename ListenerTargetT
> struct FunctionApply
<void,ListenerTargetT
>
55 template<typename FuncT
> static bool apply(
57 ListenerTargetT
const& rArg
)
64 template< typename ListenerT
> struct ListenerOperations
66 /// Notify a single one of the listeners
67 template< typename ContainerT
,
69 static bool notifySingleListener( ContainerT
& rContainer
,
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(),
79 /// Notify all listeners
80 template< typename ContainerT
,
82 static bool notifyAllListeners( ContainerT
& rContainer
,
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(
97 // true: at least one handler returned true
98 // false: not a single handler returned true
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
,
114 static bool notifySingleListener( ContainerT
& rContainer
,
117 for( const auto& rCurr
: rContainer
)
119 std::shared_ptr
<ListenerTargetT
> pListener( rCurr
.lock() );
121 if( pListener
&& func(pListener
) )
128 template< typename ContainerT
,
130 static bool notifyAllListeners( ContainerT
& rContainer
,
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
) )
148 template< typename ContainerT
>
149 static void pruneListeners( ContainerT
& rContainer
,
150 size_t nSizeThreshold
)
152 if( rContainer
.size() <= nSizeThreshold
)
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).
174 Type for the listener objects to be held
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
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
;
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.
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
221 const typename
container_type::const_iterator
aEnd( maListeners
.end() );
222 if( std::find( maListeners
.begin(),
224 rListener
) != aEnd
)
226 return true; // already added
237 void add( listener_type
const& rListener
)
242 if( isAdded(rListener
) )
243 return; // already added
245 maListeners
.push_back( rListener
);
247 ListenerOperations
<ListenerT
>::pruneListeners(
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.
263 @return false, if the listener is already added, true
266 bool addSorted( listener_type
const& rListener
)
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 )
281 std::prev(maListeners
.end()),
285 ListenerOperations
<ListenerT
>::pruneListeners(
287 MaxDeceasedListenerUllage
);
292 /** Remove listener from container
295 The listener to remove
297 @return false, if listener not found in container, true
300 bool remove( listener_type
const& rListener
)
304 const typename
container_type::iterator
aEnd( maListeners
.end() );
305 typename
container_type::iterator aIter
;
306 if( (aIter
=std::remove(maListeners
.begin(),
308 rListener
)) == aEnd
)
310 return false; // listener not found
313 maListeners
.erase( aIter
, aEnd
);
318 /// Removes all listeners in one go
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.
333 Given functor is called with listeners, until it returns true
335 @return true, if functor was successfully applied to a
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
);
348 ListenerOperations
<ListenerT
>::notifySingleListener(
353 Guard
aGuard2(*this);
354 ListenerOperations
<ListenerT
>::pruneListeners(
355 const_cast<container_type
&>(maListeners
),
356 MaxDeceasedListenerUllage
);
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.
369 Given functor is called with listeners.
371 @return true, if functor was successfully applied to at least
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
);
384 ListenerOperations
<ListenerT
>::notifyAllListeners(
389 Guard
aGuard2(*this);
390 ListenerOperations
<ListenerT
>::pruneListeners(
391 const_cast<container_type
&>(maListeners
),
392 MaxDeceasedListenerUllage
);
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
,
416 } // namespace internal
417 } // namespace slideshow
419 #endif // INCLUDED_SLIDESHOW_SOURCE_INC_LISTENERCONTAINER_HXX
421 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */