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, then 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
;
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.
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
220 const typename
container_type::const_iterator
aEnd( maListeners
.end() );
221 if( std::find( maListeners
.begin(),
223 rListener
) != aEnd
)
225 return true; // already added
236 void add( listener_type
const& rListener
)
241 if( isAdded(rListener
) )
242 return; // already added
244 maListeners
.push_back( rListener
);
246 ListenerOperations
<ListenerT
>::pruneListeners(
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.
262 @return false, if the listener is already added, true
265 bool addSorted( listener_type
const& rListener
)
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 )
280 std::prev(maListeners
.end()),
284 ListenerOperations
<ListenerT
>::pruneListeners(
286 MaxDeceasedListenerUllage
);
291 /** Remove listener from container
294 The listener to remove
296 @return false, if listener not found in container, true
299 bool remove( listener_type
const& rListener
)
303 const typename
container_type::iterator
aEnd( maListeners
.end() );
304 typename
container_type::iterator aIter
;
305 if( (aIter
=std::remove(maListeners
.begin(),
307 rListener
)) == aEnd
)
309 return false; // listener not found
312 maListeners
.erase( aIter
, aEnd
);
317 /// Removes all listeners in one go
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.
332 Given functor is called with listeners, until it returns true
334 @return true, if functor was successfully applied to a
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
);
347 ListenerOperations
<ListenerT
>::notifySingleListener(
352 Guard
aGuard2(*this);
353 ListenerOperations
<ListenerT
>::pruneListeners(
354 const_cast<container_type
&>(maListeners
),
355 MaxDeceasedListenerUllage
);
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.
368 Given functor is called with listeners.
370 @return true, if functor was successfully applied to at least
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
);
383 ListenerOperations
<ListenerT
>::notifyAllListeners(
388 Guard
aGuard2(*this);
389 ListenerOperations
<ListenerT
>::pruneListeners(
390 const_cast<container_type
&>(maListeners
),
391 MaxDeceasedListenerUllage
);
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
,
415 } // namespace internal
416 } // namespace slideshow
418 #endif // INCLUDED_SLIDESHOW_SOURCE_INC_LISTENERCONTAINER_HXX
420 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */